インターフェイスビルダーに簡単なtableViewCellビルドがあります。画像を含むUIViewが含まれています。セルを選択すると、デフォルトの青色の選択背景が表示されますが、UIViewのbackgroundColorはなくなりました。
UITableViewCellの実装ファイルは特別なことは何もしません。それはただ初期化され、自己を返し、setSelectedで行うことはすべてsuperを呼び出すことだけです。
TableViewが選択されたときにUIView backgroundColorを表示するにはどうすればよいですか?
ここでの問題は、[スーパー]実装の
- (void) setSelected:(BOOL) selected animated:(BOOL) animated;
uITableViewCellのすべての背景色をrgba(0,0,0,0)に設定します。どうして?おそらく私たちすべてに汗をかかせますか?
ビュー全体が消えるわけではありません(ビューレイヤーの境界線プロパティを変更すると、それらは保持されます)。
以下は、セルに触れた結果の関数呼び出しのシーケンスです
あなたのオプションは
残念ながら、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に続いて、カスタムUITableViewCell
実装で-(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
をオーバーライドし、[super setHighlighted:highlighted animated:animated];
を呼び出した後に背景色をリセットすると、セルが選択/強調表示されているときの背景色
-(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
[super setHighlighted:highlighted animated:animated];
myView.backgroundColor = myColor;
}
UITableViewCell
が選択されている場合、注意が必要な状態はHighlighted
とSelected
の2つです。
したがって、UITableViewCell
のサブクラスであるカスタムセルクラスがあるシナリオでは、これらの2つのメソッドを簡単にオーバーライドして、この状況を回避できます(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
}
}
ブルックスは、これがなぜ起こるのかについて素晴らしい説明をしていますが、私はより良い解決策があると思います。
サブビューで、setBackgroundColor:
好きな色に。セッターは引き続き呼び出されますが、指定した色のみが適用されます。
- (void)setBackgroundColor:(UIColor *)backgroundColor {
[super setBackgroundColor:[UIColor whiteColor]];
}
カスタムセルの次の2つのメソッドをオーバーライドする必要があります。
- (void) setSelected:(BOOL)selected animated:(BOOL)animated;
- (void) setHighlighted:(BOOL)highlighted animated:(BOOL)animated;
ご了承ください:
[super setSelected:animated:]
と[super setHighlighted:animated:]
を呼び出す必要があります。UITableViewCellSelectionStyleNone
selectionStyleを設定して、デフォルトのUITableViewCell
スタイルを無効にする必要があります。ここに実装の例:
- (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
は、iOS 7で登場したUITableViewCell
のプロパティです。代わりに、独自のセルの子ビューを使用できることに注意してください。
この問題は、iOS 13で(最終的に)解決される可能性があります。iOS13ベータ3リリースノートでこの甘い段落を見つけました。
UITableViewCellクラスは、セルが強調表示または選択されたときにcontentViewおよびそのサブビューのbackgroundColorまたはisOpaqueプロパティを変更しなくなりました。 contentView内(および含む)のセルのサブビューに不透明なbackgroundColorを設定している場合、セルが強調表示または選択されたときの外観が影響を受ける可能性があります。サブビューの問題を解決する最も簡単な方法は、backgroundColorがnilまたはclearに設定され、opaqueプロパティがfalseであることを確認することです。ただし、必要に応じて、setHighlighted(:animated :)およびsetSelected(:animated :)メソッドをオーバーライドして、移動時にサブビューのこれらのプロパティを手動で変更できます。強調表示され選択された状態との間で。 (13955336)
OK、UIViewクラスの背景色を失うことは、選択されたtableviewcellでの通常の動作です。それを防ぐ方法がわかりませんでした。これで、UIViewを、1x1の引き伸ばされた白いピクセルを含むUIImageViewに置き換えました。 glyいimoですが、動作します。
@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()
}
}
これを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()
})
}
}
概要
このソリューションでは、セルの背景色の一部をロックできますが、残りはシステムの動作によって制御されます。
Mientusの answer に基づいて、背景色を保持するビューを指定するできるソリューションを作成しました。
これにより、他のセルのサブビューのハイライト/選択時に背景を削除することができ、これがこのケースで機能する唯一のソリューションです(2つのビューには永続的な背景が必要です)。
ロックするビューのリストを含む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
UITableViewCellクラスで:
override func setSelected(_ selected: Bool, animated: Bool) {
myView.backgroundColor = UIColor.blue
}
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
myView.backgroundColor = UIColor.blue
}
この奇妙な問題に少し時間を費やしただけです。行が選択されたときに素敵なアニメーションを保持するために、UITableViewCellSelectionStyleNoneスタイルを設定したくありませんでした。しかし、提案されたアイデアはどれもうまくいきませんでした-私はsetSelectedとsetHighlightedをオーバーライドし、そこでサブビューbackgroundColorを設定しようとしました-iOSによってリセットし続け、まだ点滅しています(新しい色->古い色)。私にとっては、修正は非常に簡単でした。行が選択されると、別のView Controllerがプッシュされ、ユーザーはその画面でオプションを選択し、ユーザーの選択に基づいて色を変更するデリゲートが呼び出されます。このデリゲートでは、セルに対して[cell setSelected:NO animated:NO]を実行します。 (静的なUITableViewControllerがあり、セルへのアウトレットがあります)。おそらくdidSelectメソッドでセルの選択を解除できますが、私の場合はセグエを使用しています。
これが私の見解です。私はすべてのセルが継承するサブクラスを持っているので、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]
}
}
}
これにより、すべてのUIImageView
の問題が自動的に修正されます。
IOS 7では、setSelected:animated:
はUITableViewCell
サブクラスですが、@ Brooksのヒントに反して、[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];
}
これにより、ユーザーがセルをタップしたときにシステムのデフォルトの選択アニメーションを保持し、テーブルビューデリゲートのdidSelectRowAtIndexPath:
。
UITableViewCellクラスの関数setHighlightedをオーバーライドすることで、tableViewCellの動作を変更できます(これを継承する必要があります)。セルの背景画像を変更するコードの例:
// 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"];
}
}
インターフェイスビルダーで選択モードをグレー、ブルー、またはなしに変更することもできます。
IBを使用してtableViewCellを構築したということから、ビューをcontentView
ではなく、UITableViewCellのview
のサブビューとして追加しているかどうかを確認したいと思います。コンテンツビューは、セルに表示されるコンテンツのデフォルトのスーパービューです。
参照から:
UITableViewCellオブジェクトのコンテンツビューは、セルによって表示されるコンテンツのデフォルトのスーパービューです。追加のビューを追加するだけでセルをカスタマイズする場合は、セルが編集モードに移行したり編集モードから移行したりするときに適切に配置されるように、コンテンツビューに追加する必要があります。