現在のプロジェクトの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です。こちらがスクリーンショットです。下部のセルは、選択されているはずのように見えます。上部のセルが選択されていますが、黒と灰色の長方形の領域が表示されているはずですが、それらはなくなっています。
ここで何が起こっているのか、さらに重要なのは誰が知っていますか?これをどのように修正できますか?
起こっていることは、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]];
}
何が起こっているのか分からない場合、セルの強調表示プロセスは複雑で混乱しているように見えます。私は完全に混乱し、いくつかの大規模な実験を行いました。これは誰かを助けるかもしれない私の発見に関するメモです(誰かがこれに追加したり、反論したりすることがあれば、コメントしてください、私は確認して更新するよう努めます)
通常の「選択されていない」状態
selectedBackgroundView
はHIDDENですbackgroundView
は表示されます(contentViewが透明であれば、backgroundView
が表示されます。または、backgroundView
を定義していない場合は、UITableView
自体の背景色が表示されます)セルが選択されると、次のことがアニメーションなしですぐに発生します:
backgroundColor
がクリア(または透明に設定)され、ラベルなどのテキストの色が選択した色に変更されますselectedBackgroundView
が表示されます(このビューは常にセルのフルサイズです(カスタムフレームは無視されます。必要に応じてサブビューを使用してください)。また、backgroundColor
のsubViews
が何らかの理由で表示されないことに注意してください。 contentView
など)。 selectedBackgroundView
を定義していない場合、Cocoaは青(または灰色)のグラデーション背景を作成/挿入し、これを表示します)backgroundView
は変更されていませんセルの選択を解除すると、強調表示を削除するアニメーションが開始されます:
selectedBackgroundView
alphaプロパティは、1.0(完全に不透明)から0.0(完全に透明)までアニメーション化されます。backgroundView
は再び変更されていません(したがって、アニメーションはselectedBackgroundView
とbackgroundView
間のクロスフェードのように見えます)contentView
が「選択されていない」状態で再描画され、そのサブビューbackgroundColor
が再び表示されるようになります(アニメーションがひどく見える可能性があるため、UIView.backgroundColor
を使用しないことをお勧めしますcontentView
内)結論:
ハイライトアニメーション全体を通してbackgroundColor
を維持する必要がある場合は、代わりにbackgroundColor
のUIView
プロパティを使用しないでください(おそらく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];
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
のインスタンスにすることもできます。
私の解決策は、backgroundColor
を保存し、スーパーコールの後にそれを復元することです。
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
UIColor *bgColor = self.textLabel.backgroundColor;
[super setSelected:selected animated:animated];
self.textLabel.backgroundColor = bgColor;
}
-setHighlighted:animated:
でも同じことを行う必要があります。
TableViewメソッドをいじるのではなく、かなりエレガントなソリューションを見つけました。背景色をクリアカラーに設定することを無視するUIViewのサブクラスを作成できます。コード:
class NeverClearView: UIView {
override var backgroundColor: UIColor? {
didSet {
if UIColor.clearColor().isEqual(backgroundColor) {
backgroundColor = oldValue
}
}
}
}
Obj-Cバージョンも同様です。ここでの主なものはアイデアです
この透明性の「機能」をオンまたはオフにできるUITableViewCellカテゴリ/拡張機能を作成しました。
次の行を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
既存のすべての回答を読んだ後、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)
}
}
}
必要なのは、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;