セルを選択するとUITableViewCellサブビューが消える


178

私は、ユーザーがたとえば10色(製品によって異なります)から選択できる色選択テーブルビューを実装しています。ユーザーは他のオプション(ハードドライブ容量など)を選択することもできます。

すべての色オプションは、独自のテーブルビューセクション内にあります。

実際の色を示すtextLabelの左側に小さな正方形を表示したいと思います。

今、私は単純な正方形のUIViewを追加し、それに次のような正しい背景色を与えます:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RMProductAttributesCellID];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:RMProductAttributesCellID] autorelease];
        cell.indentationWidth = 44 - 8;

        UIView *colorThumb = [[[UIView alloc] initWithFrame:CGRectMake(8, 8, 28, 28)] autorelease];
        colorThumb.tag = RMProductAttributesCellColorThumbTag;
        colorThumb.hidden = YES;
        [cell.contentView addSubview:colorThumb];
    }

    RMProductAttribute *attr = (RMProductAttribute *)[_product.attributes objectAtIndex:indexPath.section];
    RMProductAttributeValue *value = (RMProductAttributeValue *)[attr.values objectAtIndex:indexPath.row];
    cell.textLabel.text = value.name;
    cell.textLabel.backgroundColor = [UIColor clearColor];

    UIView *colorThumb = [cell viewWithTag:RMProductAttributesCellColorThumbTag];
    colorThumb.hidden = !attr.isColor;
    cell.indentationLevel = (attr.isColor ? 1 : 0);

    if (attr.isColor) {
        colorThumb.layer.cornerRadius = 6.0;
        colorThumb.backgroundColor = value.color;
    }

    [self updateCell:cell atIndexPath:indexPath];

    return cell;
}

これは問題なく正常に表示されます。

私の唯一の問題は、「color」行を選択すると、フェードトゥブルーの選択アニメーション中に、カスタムUIView(colorThumb)が非表示になることです。選択/選択解除アニメーションが終了した直後に再び表示されますが、これにより醜いアーティファクトが生成されます。

これを修正するにはどうすればよいですか?サブビューを適切な場所に挿入しませんか?

(didSelectRowAtIndexPathには特別なものはありません。セルのアクセサリをチェックボックスに変更するか、何も変更せず、現在のindexPathの選択を解除します)。


upadteCellとは何ですか?
イダン

updateCellは、チェックマークを設定するかどうか、可用性に応じてテキストの色を選択するなど、いくつかのマイナーな調整を行いますが、セル自体またはcolorThumbに関連する実際の変更はありません。
シリル

受け入れられた回答では解決策が提供されません。解決策については、以下の私の回答を参照してください
Pavel Gurov 2016年

回答:


227

UITableViewCellセルが選択または強調表示されているときは、上書きテーブルビューセルのことで、この問題を解決することができ、すべてのサブビューの背景色を変更するsetSelected:animatedsetHighlighted:animated、ビューの背景色をリセットします。

目的Cでは:

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

    if (selected){
        self.yourView.backgroundColor = color;
    }
}

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

    if (highlighted){
        self.yourView.backgroundColor = color;
    }
}

Swift 3.1では:

override func setSelected(_ selected: Bool, animated: Bool) {
    let color = yourView.backgroundColor         
    super.setSelected(selected, animated: animated)

    if selected {
        yourView.backgroundColor = color
    }
}

override func setHighlighted(_ highlighted: Bool, animated: Bool) {
    let color = yourView.backgroundColor
    super.setHighlighted(highlighted, animated: animated)

    if highlighted {
        yourView.backgroundColor = color
    }
}

if (highlighted)if (selected)条件が必要ですか?その条件がなければうまくいくと思います。
Rishabh Tayal

@RishabhTayalそれは基本的に同じ値で変数を上書きすることを避けることです
cameloper

1
アイテムが選択されているときに背景色を変更すると、アイテムが選択解除されたときに古い(間違った)色が復元される可能性があることに注意してください。それが発生する可能性がある場合は、if(強調表示)およびif(選択)条件を削除します。
Marcel W

このアプローチはアニメーションをキャンセルするため、意味がありません。セル選択スタイルを.noneに設定することをお勧めします。
アレクサンダーダニロフ

122

これは、テーブルビューのセルが、ハイライトされた状態のコンテンツビュー内のすべてのビューの背景色を自動的に変更するためです。サブクラス化UIViewして色を描画したりUIImageView、カスタム1x1 pxのストレッチ画像を使用したりすることを検討してください。


1
私を馬鹿にします。もちろん、それだけでした。選択アニメーションが適切に発生するように、サブビューは透明でなければなりません。ありがとう!
シリル

52
または、上書きする背景色を再設定してsetHighlighted:animated:setSelected:animated:
pt2ph8

1
どういうわけか、背景色のリセットは機能しません(iOS 8.1で実行)。代わりに、ビューをサブクラス化し、setBackgroundColorを[super setBackgroundColor:[UIColor whiteColor]]としてオーバーライドすることで、これを解決しました。
bizz84 2014年

44

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

スウィフト3/4:

class NeverClearView: UIView {
    override var backgroundColor: UIColor? {
        didSet {
            if backgroundColor != nil && backgroundColor!.cgColor.alpha == 0 {
                backgroundColor = oldValue
            }
        }
    }
}

スウィフト2:

class NeverClearView: UIView {
    override var backgroundColor: UIColor? {
        didSet {
            if CGColorGetAlpha(backgroundColor!.CGColor) != 0 {
                backgroundColor = oldValue
            }
        }
    }
}

Obj-Cバージョン:

@interface NeverClearView : UIView

@end

@implementation NeverClearView

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

@end

これは素敵です。「バッジ」や「タグ」などの再利用可能なビューがあり、背景がはっきりしない場合は、簡単に最適なソリューションです。:: rant ::セルの選択を行うときにすべての子ビューを透明に設定する、@ UIKitの交絡ソリューション。少なくとも、セルの完全な高さまたは幅の子ビュー、またはNの深さの子ビューに制限します。
SimplGy 2016年

@SimplGyハイライトの深さは確かに甘いオプションですが、ちょっと-これはUIKitです。これよりもずっと悪いことが
わかりました

3
ifをCGColorGetAlpha(backgroundColor!.CGColor)== 0に変更した後、それはclearColorと等しくなかったのでうまくいきました
piltdownman7

9

問題を管理するもう1つの方法は、次のようなコアグラフィックスグラデーションでビューを塗りつぶすことです。

CAGradientLayer* gr = [CAGradientLayer layer];
gr.frame = mySubview.frame;
gr.colors = [NSArray arrayWithObjects:
                     (id)[[UIColor colorWithRed:0 green:0 blue:0 alpha:.5] CGColor]
                     ,(id)[[UIColor colorWithRed:0 green:0 blue:0 alpha:.5] CGColor]
                     , nil];

gr.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0],[NSNumber numberWithFloat:1],nil];

[mySubview.layer insertSublayer:gr atIndex:0];

うーん、私はこの正確なコードを試してみましたが、何の影響もありません。私のサブビューは、cell.contentViewのサブビューとして追加されたUILabelであり、重要な場合はiOS 6.0.1でテストしています。
ジョーストラウト2013年

上記のコードを何に適用しますか?そして、あなたは単にセルビューにラベルを追加しようとしましたか?
Agat 2013年

これは私の考えでは完璧な解決策です。レイヤーへの描画は、完全な柔軟性を維持しながら、問題に完全に対処します。UIImageViewを使用するソリューションは好きではありません。グラデーションや色を調整するのが難しくなり(毎回新しい画像を作成する必要があるため)、UIViewをサブクラス化するだけでもやり過ぎのようです。
Erik van der Neut 2014

@Lyida、私は本当にSwift開発者ではありません。(私はさらにC#-one)。しかし、私が見たところ、それはむしろ言語固有のものではありませんが、ほとんどの場合、Cocoa / iOS Frameworksロジック1です。したがって、アイデアは、ほぼ透明なCAGradientLayerをビューに配置して、要求された結果を取得することです。
Agat

9

スウィフト2.2この作品

cell.selectionStyle = UITableViewCellSelectionStyle.None

そして理由は@ Andriyによって説明されています

これは、テーブルビューのセルが、ハイライトされた状態のコンテンツビュー内のすべてのビューの背景色を自動的に変更するためです。


8

Yatheesha BL回答 に触発さ れて、私はこの透明性の「機能」をオンまたはオフにできるUITableViewCellカテゴリ/拡張機能を作成しました。

迅速

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

KeepBackgroundCellはCocoaPodsと互換性があります。GitHubで見つけることができます


7

あなたはすることができcell.selectionStyle = UITableViewCellSelectionStyleNone;、その後のbackgroundColorの設定します- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath


4

Yatheesha BLの回答に触発されました

super.setSelected(selected、animated:animated)を呼び出すと、設定した背景色がすべてクリアされます。だから、私たちは電話しませんスーパーメソッド。

Swiftの場合:

override func setSelected(selected: Bool, animated: Bool) {    
    if(selected)  {
        contentView.backgroundColor = UIColor.red 
    } else {
        contentView.backgroundColor = UIColor.white
    }
}

override func setHighlighted(highlighted: Bool, animated: Bool) {
    if(highlighted) {
        contentView.backgroundColor = UIColor.red 
    } else {
        contentView.backgroundColor = UIColor.white
    }
}

1
解決策をありがとう。+1 ishiglighted変数とsethighlightedメソッドのオーバーライドは異なります。正解は、メソッドをオーバーライドすることです。
Numan Karaaslan 2017

4

5月の場合、これはセル内のすべてのアイテムの灰色を取得しないようにするためのSeptsです(カスタムテーブルビューセルを使用している場合)。

  1. selectionStyleを.noneに設定します。 selectionStyle = .none

  2. このメソッドをオーバーライドします。

    func setHighlighted(_ highlighted:Bool、animated:Bool)

  3. スーパーを呼び出すと、スーパーセットアップのメリットが得られます。

    super.setHighlighted(ハイライト、アニメーション:アニメーション)

  4. あなたが望むロジックをこれまでハイライトしてください。

    override func setHighlighted(_ highlighted: Bool, animated: Bool) {
          super.setHighlighted(highlighted, animated: animated)
          // Your Highlighting Logic goes here...
    }

3

UITableViewCellは、何らかの理由で選択時にすべてのサブビューのbackgroundColorを変更します。

これは役立つかもしれません:

DVColorLockView

そのようなものを使用して、UITableViewが選択中にビューの色を変更しないようにします。


1

背景色を設定する代わりにビューを描画します

import UIKit

class CustomView: UIView {

    var fillColor:UIColor!

    convenience init(fillColor:UIColor!) {
        self.init()
        self.fillColor = fillColor
    }

    override func drawRect(rect: CGRect) {
        if let fillColor = fillColor {
            let context = UIGraphicsGetCurrentContext()
            CGContextSetFillColorWithColor(context, fillColor.CGColor);
            CGContextFillRect (context, self.bounds);

        }
    }


}

1

アニメーションのバグがなく(最高評価の回答のように)、サブクラス化や描画のないシンプルなソリューション-backgroundColorの代わりにレイヤーの境界線の色を設定し、非常に大きな境界線の幅を設定します。

colorThumb.layer.cornerRadius = 6
colorThumb.layer.borderWidth = colorThumb.frame.width
colorThumb.layer.borderColor = value.color

0

以下のコードを試してください:

-(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{     
[super setHighlighted:highlighted animated:animated];
//Set your View's Color here.
}

0

setSelected同様にオーバーライドすることを忘れないでくださいsetHighlighted

override func setHighlighted(highlighted: Bool, animated: Bool) {

    super.setHighlighted(highlighted, animated: animated)
    someView.backgroundColor = .myColour()
}

override func setSelected(selected: Bool, animated: Bool) {

    super.setSelected(selected, animated: animated)
    someView.backgroundColor = .myColour()
}

0

これはPavel Gurovの回答に似ていますが、どの色も永続的にすることができるという点でより柔軟です。

class PermanentBackgroundColorView: UIView {
    var permanentBackgroundColor: UIColor? {
        didSet {
            backgroundColor = permanentBackgroundColor
        }
    }

    override var backgroundColor: UIColor? {
        didSet {
            if backgroundColor != permanentBackgroundColor {
                backgroundColor = permanentBackgroundColor
            }
        }
    }
}

0

自動的な背景色の変更を無視したい1つのセルサブビューを除いて、デフォルトの選択動作を維持したいと思いました。しかし、私はまた、他の時に背景色を変更できるようにする必要がありました。

私が思いついた解決策は、サブクラス化UIViewすることでした。そのため、通常は背景色の設定を無視し、保護をバイパスする別の関数を追加します。

スウィフト4

class MyLockableColorView: UIView {
    func backgroundColorOverride(_ color: UIColor?) {
            super.backgroundColor = color
    }

    override var backgroundColor: UIColor? {
        set {
            return
        }
        get {
            return super.backgroundColor
        }
    }
}

-1

これが私の解決策です、contentViewを使用してselectionColorを表示し、それは完全に機能します

#import "BaseCell.h"

@interface BaseCell ()
@property (nonatomic, strong) UIColor *color_normal;
@property (nonatomic, assign) BOOL needShowSelection;
@end


@implementation BaseCell
@synthesize color_customSelection;
@synthesize color_normal;
@synthesize needShowSelection;

- (void)awakeFromNib
{
    [super awakeFromNib];
    [self setup];
}

- (void)setup
{
    //save normal contentView.backgroundColor
    self.color_normal = self.backgroundColor;
    if (self.color_normal == nil) {
        self.color_normal = [UIColor colorWithRGBHex:0xfafafa];
    }
    self.color_customSelection = [UIColor colorWithRGBHex:0xF1F1F1];
    self.accessoryView.backgroundColor = [UIColor clearColor];
    if (self.selectionStyle == UITableViewCellSelectionStyleNone) {
        needShowSelection = NO;
    }
    else {
        //cancel the default selection
        needShowSelection = YES;
        self.selectionStyle = UITableViewCellSelectionStyleNone;
    }
}

/*
 solution is here
 */
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    if (needShowSelection) {
        self.contentView.backgroundColor = self.backgroundColor = color_customSelection;
    }
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesCancelled:touches withEvent:event];
    if (needShowSelection) {
        self.contentView.backgroundColor = self.backgroundColor = color_normal;
    }
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];
    if (needShowSelection) {
        UIColor *color  = selected ? color_customSelection:color_normal;
        self.contentView.backgroundColor = self.backgroundColor = color;
    }
}

-1

このコードをのサブクラスに配置します UITableViewCell

Swift 3の構文

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

    if(selected) {
        lockerSmall.backgroundColor = UIColor.init(red: 233/255, green: 106/255, blue: 49/255, alpha: 1.0)
    }
}


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

    if(highlighted) {
        lockerSmall.backgroundColor = UIColor.init(red: 233/255, green: 106/255, blue: 49/255, alpha: 1.0)
    }
}

-1

ストーリーボードを使用している場合は、別のソリューションを追加します。初期設定後にを設定UIViewできないサブクラスを作成しますbackgroundColor

@interface ConstBackgroundColorView : UIView

@end

@implementation ConstBackgroundColorView

- (void)setBackgroundColor:(UIColor *)backgroundColor {
    if (nil == self.backgroundColor) {
        [super setBackgroundColor:backgroundColor];
    }
}

@end

-1

上記のバックグラウンドソリューションで問題が解決されない場合、datasourcetableViewの問題が問題の原因である可能性があります。

私にとってはBoxDataSource、デリゲートとdataSourceのtableViewメソッドを処理するためのDataSourceオブジェクト(と呼ばれる)のインスタンスを次のように作成していました。

//In cellForRowAtIndexPath, when setting up cell
let dataSource = BoxDataSource(delegate: self)
cell.tableView.dataSource = dataSource
return cell

これにより、セルがタップされるたびにdataSourceの割り当てが解除され、すべての内容が消えました。理由は、ARCの割り当て解除/ガベージコレクションの性質です。

これを修正するには、カスタムセルに移動し、データソース変数を追加する必要がありました。

//CustomCell.swift
var dataSource: BoxDataSource?

次に、dataSourceをvarcellForRowで作成したセルのdataSourceに設定する必要があるため、これはARCとの割り当てが解除されません。

cell.statusDataSource = BoxAssigneeStatusDataSource(delegate: self)
cell.detailsTableView.dataSource = cell.statusDataSource
return cell

お役に立てば幸いです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.