web-dev-qa-db-ja.com

UITableViewCellの選択時にすべての背景が消えるのはなぜですか?

現在のプロジェクトのUITableViewCellの動作が困惑しています。 UITableViewCellのかなり単純なサブクラスがあります。ベースビューにいくつかの追加の要素を追加し([self.contentView addSubview:...]を使用)、要素の背景色を設定して、要素を黒と灰色の長方形のボックスのように見せます。

テーブル全体の背景にはこのコンクリートのようなテクスチャイメージがあるため、選択した場合でも、各セルの背景は透明である必要がありますが、その場合は少し暗くなるはずです。この効果を実現するために、カスタムの半透明の選択された背景を設定しました。

UIView *background = [[[UIView alloc] initWithFrame:self.bounds] autorelease];
background.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
background.opaque = NO;

[self setSelectedBackgroundView:background];

これで背景の見た目は正しくなりますが、セルを選択すると奇妙な副作用が発生します。他のすべての背景はどういうわけかoffです。こちらがスクリーンショットです。下部のセルは、選択されているはずのように見えます。上部のセルが選択されていますが、黒と灰色の長方形の領域が表示されているはずですが、それらはなくなっています。

Screenshot of the simulator. The top cell is selected, the bottom is not.

ここで何が起こっているのか、さらに重要なのは誰が知っていますか?これをどのように修正できますか?

41
epologee

起こっていることは、TableViewCell内の各サブビューがsetSelectedメソッドとsetHighlightedメソッドを受け取ることです。 setSelectedメソッドは背景色を削除しますが、選択した状態に設定した場合は修正されます。

たとえば、それらがカスタマイズされたセルのサブビューとして追加されたUILabelsである場合、これをTableViewCell実装コードのsetSelectedメソッドに追加できます。

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

    self.textLabel.backgroundColor = [UIColor blackColor];

}

ここで、self.textLabelは、上の図に示されているラベルです。

選択したビューを追加する場所がわかりません。通常は、setSelectedメソッドに追加します。

または、UILabelをサブクラス化して、次のようにsetHighlightedメソッドをオーバーライドすることもできます。

-(void)setHighlighted:(BOOL)highlighted
{
    [self setBackgroundColor:[UIColor blackColor]];
}
55
NSDestr0yer

何が起こっているのか分からない場合、セルの強調表示プロセスは複雑で混乱しているように見えます。私は完全に混乱し、いくつかの大規模な実験を行いました。これは誰かを助けるかもしれない私の発見に関するメモです(誰かがこれに追加したり、反論したりすることがあれば、コメントしてください、私は確認して更新するよう努めます)

通常の「選択されていない」状態

  • ContentView(コード化しない限り、XIBの内容)は通常どおりに描画されます
  • selectedBackgroundViewはHIDDENです
  • backgroundViewは表示されます(contentViewが透明であれば、backgroundViewが表示されます。または、backgroundViewを定義していない場合は、UITableView自体の背景色が表示されます)

セルが選択されると、次のことがアニメーションなしですぐに発生します:

  • ContentView内のすべてのビュー/サブビューでは、backgroundColorがクリア(または透明に設定)され、ラベルなどのテキストの色が選択した色に変更されます
  • selectedBackgroundViewが表示されます(このビューは常にセルのフルサイズです(カスタムフレームは無視されます。必要に応じてサブビューを使用してください)。また、backgroundColorsubViewsが何らかの理由で表示されないことに注意してください。 contentViewなど)。 selectedBackgroundViewを定義していない場合、Cocoaは青(または灰色)のグラデーション背景を作成/挿入し、これを表示します)
  • backgroundViewは変更されていません

セルの選択を解除すると、強調表示を削除するアニメーションが開始されます:

  • selectedBackgroundView alphaプロパティは、1.0(完全に不透明)から0.0(完全に透明)までアニメーション化されます。
  • backgroundViewは再び変更されていません(したがって、アニメーションはselectedBackgroundViewbackgroundView間のクロスフェードのように見えます)
  • アニメーションが終了したときにのみ、contentViewが「選択されていない」状態で再描画され、そのサブビューbackgroundColorが再び表示されるようになります(アニメーションがひどく見える可能性があるため、UIView.backgroundColorを使用しないことをお勧めしますcontentView内)

結論:

ハイライトアニメーション全体を通してbackgroundColorを維持する必要がある場合は、代わりにbackgroundColorUIViewプロパティを使用しないでください(おそらくtableview:cellForRowAtIndexPath:を使用して)。

背景色のあるCALayer:

UIColor *bgColor = [UIColor greenColor];
CALayer* layer = [CALayer layer];
layer.frame = viewThatRequiresBGColor.bounds;
layer.backgroundColor = bgColor.CGColor;
[cell.viewThatRequiresBGColor.layer addSublayer:layer];

またはCAGradientLayer:

UIColor *startColor = [UIColor redColor];
UIColor *endColor = [UIColor purpleColor];
CAGradientLayer* gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = viewThatRequiresBGColor.bounds;
gradientLayer.colors = @[(id)startColor.CGColor, (id)endColor.CGColor];
gradientLayer.locations = @[[NSNumber numberWithFloat:0],[NSNumber numberWithFloat:1]];
[cell.viewThatRequiresBGColor.layer addSublayer:gradientLayer];

また、CALayer.border手法を使用して、カスタムUITableViewセパレーターを提供しました。

// We have to use the borderColor/Width as opposed to just setting the 
// backgroundColor else the view becomes transparent and disappears during 
// the cell's selected/highlighted animation
UIView *separatorView = [[UIView alloc] initWithFrame:CGRectMake(0, 43, 1024, 1)];
separatorView.layer.borderColor = [UIColor redColor].CGColor;
separatorView.layer.borderWidth = 1.0;
[cell.contentView addSubview:separatorView];
42
Oliver Pearmain

UITableViewCellのドラッグを開始すると、0アルファ色のサブビューでsetBackgroundColor:を呼び出します。 UIViewをサブクラス化し、setBackgroundColor:をオーバーライドして0アルファ色のリクエストを無視することで、これを回避しました。ハックに感じますが、 anyothersolutions よりもきれいです。

@implementation NonDisappearingView

-(void)setBackgroundColor:(UIColor *)backgroundColor {
    CGFloat alpha = CGColorGetAlpha(backgroundColor.CGColor);
    if (alpha != 0) {
        [super setBackgroundColor:backgroundColor];
    }
}

@end

次に、NonDisappearingViewをセルに追加し、他のサブビューを追加します。

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellIdentifier = @"cell";    
    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
        UIView *background = [cell viewWithTag:backgroundTag];
        if (background == nil) {
            background = [[NonDisappearingView alloc] initWithFrame:backgroundFrame];
            background.tag = backgroundTag;
            background.backgroundColor = backgroundColor;
            [cell addSubview:background];
        }

        // add other views as subviews of background
        ...
    }
    return cell;
}

または、cell.contentViewをNonDisappearingViewのインスタンスにすることもできます。

17

私の解決策は、backgroundColorを保存し、スーパーコールの後にそれを復元することです。

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

-setHighlighted:animated:でも同じことを行う必要があります。

6
huoxinbird

TableViewメソッドをいじるのではなく、かなりエレガントなソリューションを見つけました。背景色をクリアカラーに設定することを無視するUIViewのサブクラスを作成できます。コード:

class NeverClearView: UIView {
    override var backgroundColor: UIColor? {
        didSet {
            if UIColor.clearColor().isEqual(backgroundColor) {
                backgroundColor = oldValue
            }
        }
    }
}

Obj-Cバージョンも同様です。ここでの主なものはアイデアです

4
Pavel Gurov

この透明性の「機能」をオンまたはオフにできるUITableViewCellカテゴリ/拡張機能を作成しました。

KeepBackgroundCellを見つけることができます GitHubで

次の行をPodfileに追加して、CocoaPodsからインストールします。

pod 'KeepBackgroundCell'

使用法:

スイフト

let cell = <Initialize Cell>
cell.keepSubviewBackground = true  // Turn  transparency "feature" off
cell.keepSubviewBackground = false // Leave transparency "feature" on

Objective-C

UITableViewCell* cell = <Initialize Cell>
cell.keepSubviewBackground = YES;  // Turn  transparency "feature" off
cell.keepSubviewBackground = NO;   // Leave transparency "feature" on
2
Tim Bodeit

既存のすべての回答を読んだ後、UITableViewCellをサブクラス化するだけでSwiftを使用したエレガントなソリューションを思い付きました。

extension UIView {
    func iterateSubViews(block: ((view: UIView) -> Void)) {
        for subview in self.subviews {
            block(view: subview)
            subview.iterateSubViews(block)
        }
    }
}

class CustomTableViewCell: UITableViewCell {
   var keepSubViewsBackgroundColorOnSelection = false

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }

    // MARK: Overrides
    override func setSelected(selected: Bool, animated: Bool) {
        if self.keepSubViewsBackgroundColorOnSelection {
            var bgColors = [UIView: UIColor]()
            self.contentView.iterateSubViews() { (view) in

                guard let bgColor = view.backgroundColor else {
                    return
                }

                bgColors[view] = bgColor
            }

            super.setSelected(selected, animated: animated)

            for (view, backgroundColor) in bgColors {
                view.backgroundColor = backgroundColor
            }
        } else {
            super.setSelected(selected, animated: animated)
        }
    }

    override func setHighlighted(highlighted: Bool, animated: Bool) {
        if self.keepSubViewsBackgroundColorOnSelection {
            var bgColors = [UIView: UIColor]()
            self.contentView.iterateSubViews() { (view) in
                guard let bgColor = view.backgroundColor else {
                    return
                }

                bgColors[view] = bgColor
            }

            super.setHighlighted(highlighted, animated: animated)

            for (view, backgroundColor) in bgColors {
                view.backgroundColor = backgroundColor
            }
        } else {
            super.setHighlighted(highlighted, animated: animated)
        }
    }
}
1
Peymankh

必要なのは、setSelectedメソッドをオーバーライドし、カスタムtableViewCellクラスのtableViewCellのselectedBackgroundViewを変更することだけです。

CellForRowAtIndexPathメソッドでtableViewCellのbackgroundviewを追加する必要があります。

lCell.selectedBackgroundView = [[UIView alloc] init];

次に、以下で説明するように、setSelectedメソッドをオーバーライドしました。

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

// Configure the view for the selected state

UIImageView *lBalloonView = [self viewWithTag:102];
[lBalloonView setBackgroundColor:[[UIColor hs_globalTint] colorWithAlphaComponent:0.2]];

UITextView *lMessageTextView = [self viewWithTag:103];
lMessageTextView.backgroundColor    = [UIColor clearColor];

UILabel *lTimeLabel = [self viewWithTag:104];
lTimeLabel.backgroundColor  = [UIColor clearColor];

}

また、注目すべき最も重要な点の1つは、tableViewCell選択スタイルを変更することです。 UITableViewCellSelectionStyleNoneであってはなりません。

lTableViewCell.selectionStyle = UITableViewCellSelectionStyleGray;

enter image description here

0