Подвижность UITableViewCell исчезает при выборе ячейки

Я реализую представление таблицы color-chooser, где пользователь может выбрать, например, 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", во время анимации выделения fade-to-blue мой пользовательский UIView (colorThumb) скрыт. Он становится видимым снова сразу после окончания анимации выбора/отмены, но это вызывает уродливый артефакт.

Что мне делать, чтобы исправить это? Не вставлять ли подпункт в нужное место?

(Нет ничего особенного в didSelectRowAtIndexPath, я просто меняю принадлежность ячейки на флажок или ничего и отменяю выделение текущего indexPath).

Ответ 1

UITableViewCell меняет цвет фона всех подвыборов, когда ячейка выбрана или выделена, вы можете решить эту проблему, переопределив элемент setSelected:animated и setHighlighted:animated и сброс цвета фонового изображения.

В Objective 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
    }
}

Ответ 2

Это потому, что ячейка просмотра таблицы автоматически изменяет цвет фона всех представлений внутри представления содержимого для выделенного состояния. Вы можете рассмотреть подклассификацию UIView, чтобы нарисовать свой цвет или использовать UIImageView с пользовательским растянутым изображением размером 1x1 px.

Ответ 3

Нашел довольно элегантное решение вместо того, чтобы возиться с методами выбора/выделения таблицы TableCellCell. Вы можете создать подкласс UIView, который игнорирует установку цвета фона для очистки цвета.

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

Версия Obj-C:

@interface NeverClearView : UIView

@end

@implementation NeverClearView

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

@end

Ответ 4

Еще один способ справиться с проблемой - заполнить представление графическим градиентом, например:

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

Ответ 5

Для Swift 2.2 это работает

cell.selectionStyle = UITableViewCellSelectionStyle.None

и причина объясняется @Andriy

Это потому, что ячейка просмотра таблицы автоматически изменяет цвет фона все представления внутри содержимого для выделенного состояния.

Ответ 6

Вы можете cell.selectionStyle = UITableViewCellSelectionStyleNone;, затем установите backgroundColor в - (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath

Ответ 7

Вдохновленный Yatheesha B L ответ Я создал категорию/расширение UITableViewCell, которое позволяет включать и отключать эту функцию прозрачности.

Swift

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 совместим с CocoaPod. Вы можете найти его на GitHub

Ответ 8

UITableViewCell по какой-либо причине меняет backgroundColor всех подзонов на выбор.

Это может помочь:

DVColorLockView

Используйте что-то подобное, чтобы остановить изменение UITableView во время выбора.

Ответ 9

Вдохновленный Yatheesha B L ответ.

Если вы вызываете super.setSelected(выбранный, анимированный: анимированный), , он очистит весь цвет фона, который вы установили. Таким образом, мы не будем называть супер метод.

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

Ответ 10

Нарисуйте представление вместо установки цвета фона

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

        }
    }


}

Ответ 11

вот мое решение, используйте 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;
    }
}

Ответ 12

Попробуйте следующий код:

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

Ответ 13

На основании ответа Пола Гурова я реализовал следующее в Xamarin.iOS. Версия С#:

NeverClearView.cs

public partial class NeverClearView : UIView
{
    public NeverClearView(IntPtr handle) : base(handle)
    {
    }

    public override UIColor BackgroundColor
    {
        get
        {
            return base.BackgroundColor;
        }
        set
        {
            if (value.CGColor.Alpha == 0) return;

            base.BackgroundColor = value;
        }
    }
}

NeverClearView.designer.cs

[Register("NeverClearView")]
partial class NeverClearView
{
    void ReleaseDesignerOutlets()
    {
    }
}

Ответ 14

Не забудьте переопределить 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()
}

Ответ 15

Поместите этот код в свой подкласс 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)
    }
}

Ответ 16

Это похоже на ответ Павла Гурова, но более гибкий, поскольку он позволяет любому цвету быть постоянным.

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

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

Ответ 17

Добавление другого решения, если вы используете раскадровки. Создайте подкласс UIView, который не позволяет устанавливать backgroundColor после того, как он был первоначально установлен.

@interface ConstBackgroundColorView : UIView

@end

@implementation ConstBackgroundColorView

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

@end

Ответ 18

Если упомянутое выше фоновое решение не устраняет вашу проблему, ваша проблема может заключаться в вашем datasource для вашего tableView.

Для меня я создавал экземпляр объекта DataSource (называемый BoxDataSource) для обработки методов tableate делегата и dataSource, так:

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

Это вызывало освобождение dataSource всякий раз, когда ячейка была прослушена, и, следовательно, все содержимое исчезло. Причина заключается в том, что ARC освобождает/собирает мусор.

Чтобы исправить это, мне пришлось войти в пользовательскую ячейку, добавить переменную datasource:

//CustomCell.swift
var dataSource: BoxDataSource?

Затем вам необходимо установить источник данных в файл dataSource var, который вы только что создали в cellForRow, поэтому это не освобождается от ARC.

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

Надеюсь, что это поможет.

Ответ 19

Я хотел сохранить поведение по умолчанию, за исключением одного поднабора ячеек, что я хотел игнорировать автоматическое изменение цвета фона. Но мне также нужно было изменить цвет фона в другое время.

Решение, с которым я столкнулся, заключалось в подклассе UIView поэтому он игнорирует настройку цвета фона и добавляет отдельную функцию для обхода защиты.

Swift 4

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

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

Ответ 20

Для случая может быть, это сентябрь, чтобы избежать получения серого цвета для всех элементов в ячейке (если вы используете пользовательскую ячейку таблицы таблиц):

  1. Установите для параметра selectionStyle значение.none 👉 selectionStyle =.none

  2. Переопределите этот метод.

    func setHighlighted (_ выделено: Bool, animated: Bool)

  3. Позвоните супер, чтобы получить преимущество супер-настройки.

    super.setHighlighted (выделенный, анимированный: анимированный)

  4. Сделайте то, что когда-либо выделяет логику, которую вы хотите.

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