Programing

UITableViewCell을 선택하면 UIView backgroundColor가 사라집니다.

lottogame 2020. 11. 3. 07:33
반응형

UITableViewCell을 선택하면 UIView backgroundColor가 사라집니다.


인터페이스 빌더에 간단한 tableViewCell 빌드가 있습니다. 이미지를 포함하는 UIView를 포함합니다. 이제 셀을 선택하면 기본 파란색 선택 배경이 표시되지만 UIView의 backgroundColor는 사라집니다.

내 UITableViewCell의 구현 파일은 특별한 작업을 수행하지 않습니다. 그것은 단지 init이고 self를 반환하고 setSelected에서 내가하는 모든 것은 super를 호출하는 것입니다.

tableView를 선택할 때 UIView backgroundColor를 표시하려면 어떻게해야합니까?


여기서 문제는 [수퍼] 구현이

- (void) setSelected:(BOOL) selected animated:(BOOL) animated;

UITableViewCell의 모든 배경색을 rgba (0,0,0,0)으로 설정합니다. 왜? 우리 모두 땀을 흘리게할까요?

전체 뷰가 사라지는 것은 아닙니다 (뷰 레이어 테두리 속성을 변경하면 해당 뷰가 유지된다는 사실에 의해 입증 됨).

다음은 셀을 터치하여 발생하는 일련의 함수 호출입니다.

  1. setHighlighted
  2. touchesEnded
  3. layoutSubviews
  4. willSelectRowAtIndexPath (대리자 측)
  5. setSelected (!!! 모든 뷰 배경색이 사라지도록 지시하는 곳입니다)
  6. didSelectRowAtIndexPath (대리자 측)
  7. setSelected (다시) (흥미롭게도이 호출에서 배경색이 지워지지 않았습니다. 슈퍼 메서드 내부에서 어떤 이상한 일이 벌어지고 있습니까?)
  8. layoutSubviews (다시)

그래서 당신의 옵션은

  1. 재정의 -(void) setSelected : (BOOL) selected animated : (BOOL) animated; 호출하지 않고 [수퍼하는 setSelected : 선택된 애니메이션 : 애니메이션] . 이렇게하면 a) 코드가 UITableViewCell 하위 클래스 내부에 래핑되어 있고 b) 필요할 때만 호출되기 때문에 (필요할 때 두 번 잘 호출되지만 그에 대한 방법이있을 수 있기 때문에) 가장 기술적으로 올바른 구현을 제공합니다. 단점은 setSelected의 모든 필수 기능 (불필요한 색상 지우기 기능과 반대)을 다시 구현해야한다는 것입니다. 이제 setSelected를 올바르게 재정의하는 방법을 아직 묻지 마십시오. 귀하의 추측은 현재 내 것만 큼 좋습니다.
  2. didSelectRowAtIndexPath 에서 배경색을 다시 지정하십시오 . 이것은 인스턴스 외부에 인스턴스 코드가되어야하기 때문에 그렇게 좋지 않습니다. 반대로 필요할 때만 호출된다는 장점이 있습니다.
  3. layoutSubviews 에서 배경색을 다시 지정하십시오 . layoutSubviews가 백만 번 호출되기 때문에 이것은 전혀 좋지 않습니다! 테이블이 새로 고침 될 때마다, 스크롤 할 때마다, 할머니가 파마를받을 때마다 ... 즉, 불필요한 백그라운드 재 주장이 많고 추가 처리 오버 헤드가 많이 발생합니다. 밝은면에서는 코드를 UITableViewCell 하위 클래스에 넣습니다.

안타깝게도 setHighlighted의 배경색을 다시 지정하는 것은 setSelected에 대한 첫 번째 호출에 의해 모든 배경색이 [r : 0 b : 0 g : 0 a : 0]으로 설정되기 전에 setHighlighted가 호출되기 때문에 아무 작업도 수행하지 않습니다.

// TODO : setSelected 재정의 방법에 대한 훌륭한 설명 제공 (계속 지켜봐주세요)


- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
    UIColor *backgroundColor = self.channelImageView.backgroundColor;
    [super setHighlighted:highlighted animated:animated];
    self.channelImageView.backgroundColor = backgroundColor;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    UIColor *backgroundColor = self.channelImageView.backgroundColor;
    [super setSelected:selected animated:animated];
    self.channelImageView.backgroundColor = backgroundColor;
}

이전에는 @ P5ycH0이 말했듯이 (1x1 이미지 늘림)했지만 @Brooks를 따라 -(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated사용자 지정 UITableViewCell구현 을 재정의 하고 호출 후 배경색을 재설정 [super setHighlighted:highlighted animated:animated];하면 셀이 선택 / 강조 표시 될 때 배경색이 유지 된다는 것을 알았습니다.

-(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
    [super setHighlighted:highlighted animated:animated];
    myView.backgroundColor = myColor;
}

UITableViewCell선택 하면 주의해야 할 두 가지 상태가 있습니다. HighlightedSelected.

따라서의 하위 클래스 인 사용자 지정 셀 클래스가있는 시나리오의 UITableViewCell경우 이러한 상황 (Swift)을 피하기 위해 다음 두 가지 메서드를 쉽게 재정의 할 수 있습니다.

class MyCell: UITableViewCell {

    @IBOutlet var myView: UIView!

    override func setHighlighted(highlighted: Bool, animated: Bool) {
        let myViewBackgroundColor = myView.backgroundColor
        super.setHighlighted(highlighted, animated: animated)
        myView.backgroundColor = myViewBackgroundColor
    }

    override func setSelected(selected: Bool, animated: Bool) {
        let myViewBackgroundColor = myView.backgroundColor
        super.setSelected(selected, animated: animated)
        myView.backgroundColor = myViewBackgroundColor
    }

}

Brooks는 왜 이런 일이 발생했는지에 대한 훌륭한 설명을 제공하지만 더 나은 해결책이 있다고 생각합니다.

하위보기에서 setBackgroundColor:원하는 색상으로 재정의하십시오 . setter는 계속 호출되지만 지정된 색상 만 적용됩니다.

- (void)setBackgroundColor:(UIColor *)backgroundColor {
    [super setBackgroundColor:[UIColor whiteColor]];
}

이 문제는 (마지막으로) iOS 13에서 해결 될 수 있습니다. iOS 13 베타 3 릴리스 노트에서이 달콤한 단락을 찾았습니다.

UITableViewCell 클래스는 셀이 강조 표시되거나 선택 될 때 contentView 및 해당 하위보기의 backgroundColor 또는 isOpaque 속성을 더 이상 변경하지 않습니다. contentView 내부 (및 포함) 셀의 하위보기에서 불투명 한 backgroundColor를 설정하는 경우 셀이 강조 표시되거나 선택 될 때의 모양이 영향을받을 수 있습니다. 하위 뷰의 문제를 해결하는 가장 간단한 방법은 backgroundColor가 nil 또는 clear로 설정되어 있고 opaque 속성이 false인지 확인하는 것입니다. 그러나 필요한 경우 setHighlighted ( : animated :) 및 setSelected ( : animated :) 메서드를 재정 의하여 강조 표시된 상태와 선택된 상태로 또는 그 상태에서 이동할 때 하위 뷰에서 이러한 속성을 수동으로 변경할 수 있습니다. (13955336)

https://developer.apple.com/documentation/ios_ipados_release_notes/ios_ipados_13_beta_3_release_notes


좋아, UIView 클래스의 배경색을 잃는 것은 선택된 tableviewcell에서 정상적인 동작입니다. 나는 그것을 방지하는 방법을 알 수 없었다. 이제 UIView를 늘어난 1x1 흰색 픽셀을 포함하는 UIImageView로 교체했습니다. 못생긴 이모,하지만 작동합니다.


사용자 지정 셀에서 다음 두 가지 메서드를 재정의해야합니다.

- (void) setSelected:(BOOL)selected animated:(BOOL)animated;
- (void) setHighlighted:(BOOL)highlighted animated:(BOOL)animated;

참고 :

  • 사용자 정의 구현 또는 해당 메소드의 시작 부분에서 [super setSelected:animated:]호출해야 [super setHighlighted:animated:]합니다.
  • UITableViewCellSelectionStyleNone기본 UITableViewCell스타일 을 비활성화하려면 사용자 지정 셀에 selectionStyle을 설정해야합니다 .

다음은 구현 예입니다.

- (void) setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
    [super setHighlighted:highlighted animated:animated];
    [self setHighlightedSelected:highlighted animated:animated];
}

- (void) setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];
    [self setHighlightedSelected:selected animated:animated];
}

- (void) setHighlightedSelected:(BOOL)selected animated:(BOOL)animated
{
    void(^selection_block)(void) =
    ^
    {
        self.contentView.backgroundColor = selected ? SELECTED_BACKGROUND_COLOR : NORMAL_BACKGROUND_COLOR;
    };

    if(animated)
    {
        [UIView animateWithDuration:SELECTION_ANIMATION_DURATION
                              delay:0.0
                            options:UIViewAnimationOptionBeginFromCurrentState
                         animations:selection_block
                         completion:NULL];
    }
    else
        selection_block();
}

contentView속성은 UITableViewCelliOS 7에 나타납니다. 셀 대신 자체 셀의 하위보기 또는보기를 사용할 수 있습니다.


이것을 UITableViewCell에 추가하십시오.

override func setHighlighted(highlighted: Bool, animated: Bool) {
    super.setHighlighted(false, animated: animated)
    if highlighted {
        self.backgroundColor = UIColor.blueColor()
    }else{
        UIView.animateWithDuration(0.2, animations: {
            self.backgroundColor = UIColor.clearColor()
        })
    }
}

@Brooks의 답변과 관련하여 이것이 Swift 및 iOS8 / iOS9에서 작동하도록하기 위해 수행 한 작업입니다.

  • setSelected재정의setHighlighted
  • 슈퍼라고 부르지 마
  • 클리어 아웃 contentView.backgroundColor, 그것은 셀 (예 : 액세서리)의 전체 폭에 걸쳐 스팬이 없기 때문에.
  • backgroundColor셀 자체를 사용하고 그에 따라 설정하십시오.

    class AwesomeTableViewCell: UITableViewCell {
    
        private struct Constants {
    
            static var highlightedColor = UIColor.greenColor()
            static var selectedColor = UIColor.redColor()
    
            static let animationTime = NSTimeInterval(0.2)
        }
    
        override func awakeFromNib() {
            super.awakeFromNib()
    
            contentView.backgroundColor = UIColor.clearColor()
            backgroundColor = AppContext.sharedInstance.theme.colors.background
        }
    
        override func setHighlighted(highlighted: Bool, animated: Bool) {
            if animated {
                UIView.animateWithDuration(Constants.animationTime, animations: { () -> Void in
                    self.setHighlighted(highlighted)
                })
            } else {
                self.setHighlighted(highlighted)
            }
        }
    
        override func setSelected(selected: Bool, animated: Bool) {
    
            if animated {
                UIView.animateWithDuration(Constants.animationTime, animations: { () -> Void in
                    self.setSelected(selected)
                })
            } else {
                self.setSelected(selected)
            }
        }
    
        private func setHighlighted(highlighted: Bool) {
    
            backgroundColor = highlighted ? Constants.highlightedColor : UIColor.whiteColor()
        }
    
        private func setSelected(selected: Bool) {
    
            backgroundColor = selected ? Constants.selectedColor : UIColor.whiteColor()
        }
    }
    

요약

이 솔루션 을 사용하면 셀의 배경색 중 일부잠그고 나머지는 시스템 동작에 의해 제어 할 수 있습니다.


mientus의 답변을 바탕으로 배경색 을 유지할 뷰지정할 수있는 솔루션을 만들었습니다 .

그래도 다른 셀 하위 뷰가 강조 표시 / 선택시 배경을 제거 할 수 있으며 우리의 경우에 작동하는 유일한 솔루션입니다 (영구적 인 배경이 필요한 두 뷰).

BackgroundLockable잠글 뷰 목록이 포함 프로토콜을 사용하고 색상을 유지하면서 클로저를 실행하는 프로토콜 지향 접근 방식을 사용했습니다 .

protocol BackgroundLockable {
    var lockedBackgroundViews: [UIView] { get }
    func performActionWithLockedViews(_ action: @escaping () -> Void)
}

extension BackgroundLockable {
    func performActionWithLockedViews(_ action: @escaping () -> Void) {
        let lockedViewToColorMap = lockedBackgroundViews.reduce([:]) { (partialResult, view) -> [UIView: UIColor?] in
            var mutableResult = partialResult
            mutableResult[view] = view.backgroundColor
            return mutableResult
        }

        action()

        lockedViewToColorMap.forEach { (view: UIView, color: UIColor?) in
            view.backgroundColor = color
        }
    }
}

그런 다음 UITableViewCell기본 (슈퍼) 동작을 호출하는 것과 관련하여 프로토콜의 클로저를 실행하기 위해 강조 표시 및 선택을 재정의 하는 하위 클래스가 있습니다.

class LockableBackgroundTableViewCell: UITableViewCell, BackgroundLockable {

    var lockedBackgroundViews: [UIView] {
        return []
    }

    override func setHighlighted(_ highlighted: Bool, animated: Bool) {
        performActionWithLockedViews {
            super.setHighlighted(highlighted, animated: animated)
        }
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        performActionWithLockedViews {
            super.setSelected(selected, animated: animated)
       }
    }
}

이제 일부 셀에 잠금 동작을 쉽게 추가하기 위해 셀 클래스에서 프로토콜 을 서브 클래스 LockableBackgroundTableViewCell하거나 사용 하기 만하면됩니다 BackgroundLockable!

class SomeCell: LockableBackgroundTableViewCell {

    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var icon: UIImageView!
    @IBOutlet weak var button: UIButton!

    override var lockedBackgroundViews: [UIView] {
        return [label, icon]
    }
}

Swift 4

In your UITableViewCell class:

override func setSelected(_ selected: Bool, animated: Bool) {
    myView.backgroundColor = UIColor.blue
}

override func setHighlighted(_ highlighted: Bool, animated: Bool) {
    myView.backgroundColor = UIColor.blue
}

From that you said you built a tableViewCell using IB, I'd like to check whether you are adding your view as a subview of contentView of UITableViewCell, not view. The content view is the default superview for content displayed by the cell.

From the reference:

The content view of a UITableViewCell object is the default superview for content displayed by the cell. If you want to customize cells by simply adding additional views, you should add them to the content view so they will be positioned appropriately as the cell transitions into and out of editing mode.


You can change the behavior of the tableViewCell by overriding the function setHighlighted in UITableViewCell class (you will need to inherit from it). Example of my code where I change the background image of my cell :

// animate between regular and highlighted state
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated; {
    [super setHighlighted:highlighted animated:animated];

    //Set the correct background Image
    UIImageView* backgroundPicture = (UIImageView*)[self viewWithTag:HACK_BACKGROUND_VIEW_TAG];
    if (highlighted) {
        backgroundPicture.image = [UIImage imageNamed:@"FondSelected.png"]; 
    }
    else {
        backgroundPicture.image = [UIImage imageNamed:@"Fond.png"]; 
    }
}

You can also change the selection mode to gray, blue or none in the interface builder.


In iOS 7, what worked for me is to override setSelected:animated: in the UITableViewCell subclass, but contrary to @Brooks' tip, I called [super setSelected:selected animated:animated].

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    // Reassert the background color of the color view so that it shows
    // even when the cell is highlighted for selection.
    self.colorView.backgroundColor = [UIColor blueColor];
}

This lets me keep the system's default selection animation when the user taps on the cell, and also to deselect it in the table view delegate's didSelectRowAtIndexPath:.


Just spent some time on this weird issue. I did not want to set UITableViewCellSelectionStyleNone style to preserve nice animation when my row was selected. But none of suggested ideas worked for me - I was trying to override setSelected and setHighlighted and set my subview backgroundColor there - it was keeping resetting by iOS and still blinking (new color -> old color). For me the fix was quite simple. When my row is selected another view controller is pushed, user chooses some option on that screen and delegate is called where I change the color based on user selection. In this delegate I just do [cell setSelected:NO animated:NO] for my cell. (I have static UITableViewController and have outlets to cells). You could probably deselect cell in didSelect method but in my case I'm using segues.


Here's my take on it. I have a subclass that all my cell inherit from, so that's the way I do it to avoid the background change in my UIImageViews:

    override func setHighlighted(highlighted: Bool, animated: Bool) {
    var backgroundColors = [UIView: UIColor]()

    for view in contentView.subviews as [UIView] {
        if let imageView = view as? UIImageView {
            backgroundColors[imageView] = imageView.backgroundColor
        }
    }

    super.setHighlighted(highlighted, animated: animated)

    for view in contentView.subviews as [UIView] {
        if let imageView = view as? UIImageView {
            imageView.backgroundColor = backgroundColors[imageView]
        }
    }
}

override func setSelected(selected: Bool, animated: Bool) {
    var backgroundColors = [UIView: UIColor]()

    for view in contentView.subviews as [UIView] {
        if let imageView = view as? UIImageView {
            backgroundColors[imageView] = imageView.backgroundColor
        }
    }

    super.setSelected(selected, animated: animated)

    for view in contentView.subviews as [UIView] {
        if let imageView = view as? UIImageView {
            imageView.backgroundColor = backgroundColors[imageView]
        }
    }
}

This automaticlly fix the issue for all UIImageView.

참고URL : https://stackoverflow.com/questions/5222736/uiview-backgroundcolor-disappears-when-uitableviewcell-is-selected

반응형