Subview UITableViewCell biến mất khi ô được chọn


178

Tôi đang triển khai chế độ xem bảng chọn màu trong đó người dùng có thể chọn trong số 10 màu (tùy thuộc vào sản phẩm). Người dùng cũng có thể chọn các tùy chọn khác (như dung lượng ổ cứng, ...).

Tất cả các tùy chọn màu sắc nằm trong phần xem bàn riêng của họ.

Tôi muốn hiển thị một hình vuông nhỏ ở bên trái của textLabel hiển thị màu thực tế.

Ngay bây giờ tôi đang thêm một UIView hình vuông đơn giản, cung cấp cho nó màu nền chính xác, như thế này:

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

Điều này hiển thị tốt mà không có vấn đề.

Vấn đề duy nhất của tôi là khi tôi chọn một hàng "màu", trong khi hoạt ảnh lựa chọn mờ dần sang màu xanh, UIView tùy chỉnh của tôi (colorThumb) bị ẩn. Nó được nhìn thấy một lần nữa ngay sau khi hoạt hình lựa chọn / giải trừ kết thúc, nhưng điều này tạo ra một tạo tác xấu xí.

Tôi nên làm gì để sửa lỗi này? Tôi không chèn subview vào đúng chỗ?

(Không có gì đặc biệt trong didSelectRowAtIndexPath, tôi chỉ thay đổi phụ kiện của ô thành hộp kiểm hoặc không có gì và bỏ chọn indexPath hiện tại).


UpadteCell tất cả về cái gì?
Idan

updateCell thực hiện một số điều chỉnh nhỏ như đặt dấu kiểm hay không, chọn màu văn bản tùy thuộc vào tính khả dụng, ... nhưng không có thay đổi thực sự liên quan đến chính ô hoặc colorThumb.
Cyrille

câu trả lời được chấp nhận không cung cấp giải pháp, hãy xem câu trả lời của tôi dưới đây để biết giải pháp
Pavel Gurov

Câu trả lời:


227

UITableViewCellthay đổi màu nền của tất cả các quan điểm phụ khi tế bào được chọn hoặc đánh dấu, Bạn có thể giải quyết vấn đề này bằng cách ghi đè tableView di động của setSelected:animatedsetHighlighted:animatedvà đặt màu nền xem.

Trong mục tiêu 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;
    }
}

Trong 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
    }
}

Chúng ta có cần if (highlighted)và các if (selected)điều kiện? Tôi nghĩ nó sẽ hoạt động nếu chúng ta không có những điều kiện đó.
Rishabh Tayal

@RishabhTayal về cơ bản là để tránh ghi đè biến có cùng giá trị
cameloper

1
Lưu ý rằng khi bạn thay đổi màu nền trong khi mục được chọn, màu cũ (sai) có thể được khôi phục khi mục đó không được chọn. Nếu điều đó có thể xảy ra, hãy loại bỏ các điều kiện if (được tô sáng) và if (được chọn).
Marcel W

Cách tiếp cận này hủy bỏ hình ảnh động, vì vậy nó không có ý nghĩa. Tốt hơn để đặt kiểu chọn ô thành .none.
Alexander Danilov

122

Đó là vì ô xem bảng tự động thay đổi màu nền của tất cả các chế độ xem trong chế độ xem nội dung cho trạng thái được tô sáng. Bạn có thể xem xét phân lớp UIViewđể vẽ màu của mình hoặc sử dụng UIImageViewvới hình ảnh kéo dài 1x1 px tùy chỉnh.


1
Câm tôi. Tất nhiên là như vậy, các cuộc phỏng vấn phải minh bạch để hoạt hình lựa chọn có thể xảy ra đúng. Cảm ơn!
Cyrille

52
Hoặc bạn có thể đặt lại màu nền ghi đè setHighlighted:animated:setSelected:animated:
pt2ph8

1
Bằng cách nào đó, việc đặt lại màu nền không phù hợp với tôi (chạy trên iOS 8.1). Thay vào đó, đã giải quyết vấn đề này bằng cách phân lớp chế độ xem của tôi và ghi đè setBackgroundColor thành [super setBackgroundColor: [UIColor whiteColor]].
bizz84

44

Tìm thấy một giải pháp khá thanh lịch thay vì làm rối với các phương thức chọn / tô sáng của bảngViewCell. Bạn có thể tạo một lớp con của UIView mà bỏ qua việc đặt màu nền của nó thành màu rõ ràng.

Swift 3/4:

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

Swift 2:

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

Phiên bản Obj-C:

@interface NeverClearView : UIView

@end

@implementation NeverClearView

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

@end

Cái này thật đáng yêu. Dễ dàng là giải pháp tốt nhất nếu bạn có một số chế độ xem có thể sử dụng lại như "huy hiệu" hoặc "thẻ" không bao giờ có nền rõ ràng. :: rant :: thật là một giải pháp khó hiểu @UIKit, đặt tất cả các chế độ xem con thành trong suốt khi bạn thực hiện lựa chọn ô. Ít nhất là giới hạn đối với các chế độ xem con có chiều cao hoặc chiều rộng đầy đủ của ô hoặc các chế độ xem ở độ sâu N.
SimplGy

@SimplGy Độ sâu của việc làm nổi bật sẽ thực sự là một lựa chọn ngọt ngào, nhưng này - đây là UIKit, tôi đã thấy những điều SO tồi tệ hơn thế này =)
Pavel Gurov

3
Làm việc cho tôi sau khi tôi thay đổi if thành CGColorGetAlpha (nềnColor! .CGColor) == 0 vì nó không bằng ClearColor
piltdownman7

9

Một cách khác để quản lý vấn đề là lấp đầy khung nhìn bằng gradient đồ họa lõi, như:

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, tôi đang thử mã chính xác này và nó không có tác dụng gì với tôi cả. Subview của tôi là một UILabel được thêm dưới dạng một subview của cell.contentView và thử nghiệm trong iOS 6.0.1, trong trường hợp có vấn đề.
Joe Strout

Bạn áp dụng mã trên để làm gì? Và bạn đã thử thêm nhãn đơn giản vào chế độ xem ô chưa?
Agat

Đây là giải pháp hoàn hảo theo ý kiến ​​của tôi. Vẽ tới lớp giải quyết vấn đề một cách hoàn hảo, trong khi vẫn giữ được sự linh hoạt hoàn toàn. Tôi không thích giải pháp sử dụng UIImageView, vì điều đó khó điều chỉnh độ dốc hoặc màu sắc hơn (mỗi lần bạn phải tạo một hình ảnh mới) và phân lớp UIView chỉ vì điều này có vẻ quá mức.
Erik van der Neut

@Lyida, tôi không thực sự là nhà phát triển Swift. (Tôi thậm chí nhiều hơn C # -one). Nhưng từ những gì tôi đã thấy, đó không phải là điều cụ thể về ngôn ngữ, tuy nhiên, chủ yếu là logic của Khung / ca cao. Vì vậy, ý tưởng chỉ là đặt CAGradientLayer gần như trong suốt vào tầm nhìn của bạn để có được kết quả được yêu cầu.
Agat

9

Đối với Swift 2.2 , công việc này

cell.selectionStyle = UITableViewCellSelectionStyle.None

và lý do được giải thích bởi @ Andriy

Đó là vì ô xem bảng tự động thay đổi màu nền của tất cả các chế độ xem trong chế độ xem nội dung cho trạng thái được tô sáng.


8

Lấy cảm hứng từ Yatheesha BL 's câu trả lời tôi đã tạo ra một loại UITableViewCell / extension cho phép bạn bật và tắt tính minh bạch này 'tính năng'.

Nhanh

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

Mục tiêu-C

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

KeepBackgroundCell tương thích với Cốc Cốc. Bạn có thể tìm thấy nó trên GitHub


7

Bạn có thể cell.selectionStyle = UITableViewCellSelectionStyleNone;, sau đó đặt nềnColor tại- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath


4

Lấy cảm hứng từ câu trả lời của Yeditesha BL .

Nếu bạn gọi super.setSelected (đã chọn, hoạt hình: hoạt hình), nó sẽ xóa tất cả màu nền bạn đặt . Vì vậy, chúng tôi sẽ không gọi siêu phương pháp.

Trong 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
Cảm ơn giải pháp. +1 Ghi đè biến ishiglighted và phương thức sethighlighted là những thứ khác nhau. câu trả lời đúng là ghi đè phương thức.
Numan Karaaslan

4

Đối với trường hợp có thể, Đây là Septs để tránh lấy màu xám cho tất cả các mục trong ô (trong trường hợp bạn đang sử dụng ô xem bảng tùy chỉnh):

  1. Đặt lựa chọn Kiểu thành .none selectionStyle = .none

  2. Ghi đè phương thức này.

    func setHighlighted (_ được tô sáng: Bool, hoạt hình: Bool)

  3. Gọi siêu, để có được lợi ích của siêu thiết lập.

    super.setHighlighted (tô sáng, hoạt hình: hoạt hình)

  4. Làm những gì từng làm nổi bật logic bạn muốn.

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

3

UITableViewCell thay đổi màu nền của tất cả các cuộc phỏng vấn về lựa chọn vì một số lý do.

Điều này có thể giúp:

DVColorLockView

Sử dụng một cái gì đó như thế để ngăn UITableView thay đổi màu xem của bạn trong khi lựa chọn.


1

Vẽ khung nhìn thay vì đặt màu nền

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

Giải pháp SIMPLEST không có lỗi với hình ảnh động (như trong câu trả lời được xếp hạng hàng đầu) và không có phân lớp và bản vẽ - đặt màu đường viền của lớp thay vì màu nền và đặt độ rộng đường viền rất lớn.

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

0

Hãy thử mã sau:

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

0

Đừng quên ghi đè setSelectedcũng như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

Điều này tương tự như câu trả lời của Pavel Gurov, nhưng linh hoạt hơn ở chỗ nó cho phép bất kỳ màu nào là vĩnh viễn.

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

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

0

Tôi muốn giữ hành vi lựa chọn mặc định ngoại trừ một ô phụ mà tôi muốn bỏ qua thay đổi màu nền tự động. Nhưng tôi cũng cần có thể thay đổi màu nền vào những lúc khác.

Giải pháp tôi đưa ra là phân lớp UIViewđể nó bỏ qua việc thiết lập màu nền bình thường và thêm một chức năng riêng biệt để bỏ qua việc bảo vệ.

Swift 4

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

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

-1

Đây là giải pháp của tôi, sử dụng contentView để hiển thị lựa chọn Màu sắc, nó hoạt động hoàn hảo

#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

Đặt mã này trong lớp con của bạn UITableViewCell

Cú pháp 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

Thêm một giải pháp khác nếu bạn đang sử dụng bảng phân cảnh. Tạo một lớp con UIViewkhông cho phép backgroundColorthiết lập sau khi được đặt ban đầu.

@interface ConstBackgroundColorView : UIView

@end

@implementation ConstBackgroundColorView

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

@end

-1

Nếu giải pháp nền được đề cập ở trên không khắc phục được sự cố của bạn, vấn đề của bạn có thể nằm ở bạn datasource bạn.

Đối với tôi, tôi đã tạo một thể hiện của một đối tượng DataSource (được gọi BoxDataSource) để xử lý các phương thức bảngView và dataSource của đại biểu, như vậy:

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

Điều này đã khiến dataSource bị hủy bỏ bất cứ khi nào ô được gõ, và do đó tất cả các nội dung biến mất. Lý do là, tính chất thu gom / thu gom rác ARC.

Để khắc phục điều này, tôi đã phải đi vào ô tùy chỉnh, thêm một biến nguồn dữ liệu:

//CustomCell.swift
var dataSource: BoxDataSource?

Sau đó, bạn cần đặt dataSource thành dataSource của ô var mà bạn vừa tạo trong cellForRow, vì vậy điều này không được giải quyết với ARC.

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

Mong rằng sẽ giúp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.