Hücre seçildiğinde UITableViewCell alt görünümü kaybolur


178

Kullanıcı, örneğin 10 renk arasından seçim yapabileceği bir renk seçici tablo görünümü uyguluyorum (ürüne bağlı). Kullanıcı ayrıca diğer seçenekleri de seçebilir (sabit sürücü kapasitesi, ... gibi).

Tüm renk seçenekleri kendi tablo görünümü bölümünün içindedir.

Metin renginin solunda gerçek rengi gösteren küçük bir kare görüntülemek istiyorum.

Şu anda basit bir kare UIView ekliyorum, doğru arka plan rengini ver, şöyle:

- (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;
}

Bu sorunsuz görüntüler.

Tek sorunum, bir "renk" satırı seçtiğimde, solmaya-mavi seçim animasyonu sırasında özel UIView'imin (colorThumb) gizlenmesi. Seçim / seçim kaldırma animasyonu sona erdikten hemen sonra tekrar görünür hale gelir, ancak bu çirkin bir eser üretir.

Bunu düzeltmek için ne yapmalıyım? Alt görünümü doğru yere eklemiyor muyum?

(DidSelectRowAtIndexPath'te özel bir şey yok, sadece hücrenin aksesuarını bir onay kutusuna veya hiçbir şeye değiştirmem ve mevcut indexPath'in seçimini kaldırıyorum).


Peki ne hakkında?
Idan

updateCell, onay işaretini ayarlamak ya da ayarlamak, kullanılabilirliğe bağlı olarak metin rengini seçmek gibi küçük küçük değişiklikler yapar, ancak hücrenin kendisi veya colorThumb ile ilgili gerçek bir değişiklik yoktur.
Cyrille

kabul edilen cevap çözüm sağlamaz, aşağıdaki çözüm için cevabım bakın
Pavel Gurov

Yanıtlar:


227

UITableViewCellHücre seçildiğinde veya vurgulanır zaman ağır basan Tableview hücre en bu sorunu çözün edebilir, tüm alt görüşlerin arka plan rengini değiştirir setSelected:animatedve setHighlighted:animatedve görünümü arka plan rengini sıfırlama.

Hedef 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'de:

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)Ve if (selected)şartlarına ihtiyacımız var mı? Bu şartlara sahip olmadığımızda işe yarayacağını düşünüyorum.
Rishabh Tayal

@RishabhTayal aynı değere sahip değişkeni geçersiz kılma önlemek için temelde
cameloper

1
Öğe seçiliyken arka plan rengini değiştirdiğinizde, öğenin seçimi kaldırıldığında eski (yanlış) rengin geri yüklenebileceğini unutmayın. Böyle bir durumda, if (vurgulanmış) ve if (seçili) koşullarını kaldırın.
Marcel W

Bu yaklaşım animasyonu iptal eder, bu yüzden bir anlamı yoktur. Hücre seçim stilini .none olarak ayarlamak daha iyidir.
Alexander Danilov

122

Bunun nedeni, tablo görünümü hücresinin, vurgulanan durum için içerik görünümündeki tüm görünümlerin arka plan rengini otomatik olarak değiştirmesidir. Renginizi UIViewçizmek veya UIImageViewözel 1x1 piksel uzatılmış görüntü ile kullanmak için alt sınıflamayı düşünebilirsiniz .


1
Aptal bana. Elbette öyleydi, seçim animasyonunun düzgün bir şekilde gerçekleşebilmesi için alt görünümlerin şeffaf olması gerekir. Teşekkürler!
Cyrille

52
Veya arka plan rengini geçersiz setHighlighted:animated:setSelected:animated:
kılmayı

1
Bir şekilde arka plan rengini sıfırlamak benim için işe yaramadı (iOS 8.1'de çalışıyor). Bunun yerine, görünümümü alt sınıflandırarak ve setBackgroundColor'u [super setBackgroundColor: [UIColor whiteColor]] olarak geçersiz kılarak çözüldü.
bizz84

44

TableViewCell seçim / vurgulama yöntemleri ile uğraşmak yerine oldukça zarif bir çözüm bulundu. Arka plan rengini açık renge ayarlamayı yok sayan bir UIView alt sınıfı oluşturabilirsiniz.

Hızlı 3/4:

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

Hızlı 2:

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

Obj-C sürümü:

@interface NeverClearView : UIView

@end

@implementation NeverClearView

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

@end

Bu çok hoş. Asla net bir arka plana sahip olmaması gereken bir "rozet" veya "etiket" gibi yeniden kullanılabilir bir görünümünüz varsa, kolayca en iyi çözüm. :: rant :: ne bir kafa karıştırıcı çözüm @UIKit, bir hücre seçimi yaptığınızda tüm alt görünümleri saydam olarak ayarlayın. En azından hücrenin tam yüksekliği veya genişliği olan veya N derinliğindeki çocuk görünümleriyle sınırlandırın.
SimplGy

@SimplGy Vurgulamanın derinliği gerçekten tatlı bir seçenek olurdu, ama hey - bu UIKit, bundan çok daha kötü şeyler gördüm =)
Pavel Gurov

3
Eğer açık renk için eşit değildi çünkü CGColorGetAlpha (backgroundColor! .CGColor) == 0 olarak değiştirdikten sonra benim için çalıştı
piltdownman7 22:16

9

Sorunu yönetmenin başka bir yolu da görünümü temel grafik gradyanıyla doldurmaktır:

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];

Hmm, bu tam kodu deniyorum ve benim için hiç bir etkisi yok. Alt görünümüm, cell.contentView öğesinin alt görünümü olarak eklenen ve önemli olması durumunda iOS 6.0.1 altında test edilen bir UILabel.
Joe Strout

Yukarıdaki kodu neye uyguluyorsunuz? Etiketi yalnızca hücre görünümüne eklemeye çalıştınız mı?
Agat

Bence bu mükemmel bir çözüm. Katmana çizim, tam esnekliği korurken sorunu mükemmel bir şekilde ele alır. Bir UIImageView kullanma çözümünü sevmiyorum, çünkü o zaman gradyanı veya rengi ayarlamak daha zor (her seferinde yeni bir görüntü yapmak zorunda kalacaksınız) ve UIView'i alt sınıflandırma sadece aşırıya kaçmış gibi görünüyor.
Erik van der Neut

@Lyida, ben gerçekten Swift-geliştirici değilim. (Daha da fazla C #). Ancak gördüğüm kadarıyla bu, dile özgü bir şey değil, ancak çoğunlukla Cocoa / iOS Frameworks mantığı. Bu nedenle, fikir, istenen sonucu elde etmek için neredeyse şeffaf CAGradientLayer'ı görünümünüze yerleştirmektir.
Agat

9

For Swift 2.2 Bu eserler

cell.selectionStyle = UITableViewCellSelectionStyle.None

ve sebep @ Andriy

Bunun nedeni, tablo görünümü hücresinin, vurgulanan durum için içerik görünümündeki tüm görünümlerin arka plan rengini otomatik olarak değiştirmesidir.


8

Esinlenerek Yatheesha BL 'ın cevabı sana ve bu şeffaflık 'özelliği' kapatmak sağlayan bir UITableViewCell kategori / uzantısı yarattı.

hızlı

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 ile uyumludur. GitHub'da bulabilirsiniz


7

Şunları yapabilirsiniz cell.selectionStyle = UITableViewCellSelectionStyleNone;, daha sonra backgroundColor ayarlanmış- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath


4

Yatheesha BL'nin cevabından ilham aldı .

Super.setSelected (seçili, canlandırılmış: canlandırılmış) ayarladığınız tüm arka plan renkleri silinir . Yani, süper yöntemi çağırmayacağız .

Swift'te:

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
Çözüm için teşekkürler. +1 ishiglighted değişkenini ve sethighlighted yöntemini geçersiz kılmak farklı şeylerdir. doğru cevap yöntemi geçersiz kılmaktır.
Numan Karaaslan

4

Durum için, bu, hücredeki tüm öğeler için gri renk elde edilmesini önlemek için Septs'tir (özel tablo görünümü hücresi kullanıyorsanız):

  1. SelectionStyle öğesini .none olarak ayarlayın 👉 selectionStyle = .none

  2. Bu yöntemi geçersiz kılın.

    func setHighlighted (_ vurgulanan: Bool, hareketli: Bool)

  3. Süper kurulumdan yararlanmak için super'i arayın.

    super.setHighlighted (vurgulanmış, canlandırılmış: canlandırılmış)

  4. İstediğiniz mantığı vurgulayın.

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

3

UITableViewCell, seçimdeki tüm alt görüntülerin backgroundColor'unu bir nedenden dolayı değiştirir.

Bu yardımcı olabilir:

DVColorLockView

Seçim sırasında UITableView öğesinin görünüm renginizi değiştirmesini engellemek için böyle bir şey kullanın.


1

Arka plan rengini ayarlamak yerine görünümü çizin

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

Animasyonlu hatalar (en yüksek puanlı yanıtta olduğu gibi) ve alt sınıflandırma ve çizim olmadan SIMPLEST çözümü - backgroundColor yerine katmanın kenarlık rengini ayarlayın ve çok büyük kenarlık genişliği ayarlayın.

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

0

Aşağıdaki kodu deneyin:

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

0

Geçersiz kılmayı setSelectedda unutmayınsetHighlighted

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

Bu Pavel Gurov'un cevabına benzer, ancak herhangi bir rengin kalıcı olmasına izin verdiği için daha esnektir.

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

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

0

Otomatik arka plan renk değişikliğini yoksaymak istediğim bir hücre alt görünümü dışında varsayılan seçim davranışını korumak istedim. Ama arka plan rengini başka zamanlarda da değiştirebilmem gerekiyordu.

Geldiğim çözüm UIView, arka plan rengini normal olarak ayarlamayı göz ardı etmek ve korumayı atlamak için ayrı bir işlev eklemek için alt sınıfa geçmekti.

Hızlı 4

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

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

-1

İşte benim çözümüm, selectionColor'ı göstermek için contentView kullanın, mükemmel çalışıyor

#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

Bu kodu şunun alt sınıfınıza yerleştirin: UITableViewCell

Swift 3 sözdizimi

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

Film şeridi kullanıyorsanız başka bir çözüm eklemek. Başlangıçta ayarlandıktan sonra ayarlanmasına UIViewizin vermeyen bir alt sınıf oluşturun backgroundColor.

@interface ConstBackgroundColorView : UIView

@end

@implementation ConstBackgroundColorView

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

@end

-1

Yukarıda belirtilen arka plan çözümü sorununuzu çözmüyorsa, sorununuz datasourceTableView'inizde olabilir.

Benim için, BoxDataSourcetemsilci ve dataSource tableView yöntemlerini işlemek için bir DataSource nesnesinin (çağrılan ) bir örneğini oluşturuyordum :

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

Bu, hücreye her dokunduğunda dataSource'un ayrılmasına neden oldu ve böylece tüm içerik kayboldu. Nedeni, ARC dağıtma / çöp toplama doğasıdır.

Bunu düzeltmek için özel hücreye gitmek, bir datasource değişkeni eklemek zorunda kaldım:

//CustomCell.swift
var dataSource: BoxDataSource?

Ardından, dataSource'u varcellForRow'da oluşturduğunuz hücrenin dataSource değerine ayarlamanız gerekir , böylece bu ARC ile ayrılmaz.

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

Umarım yardımcı olur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.