Підвибір 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;
}

Це відображається нормально без проблем.

Моя єдина проблема полягає в тому, що коли я вибираю "кольоровий" рядок, під час анімації вицвілого до синього кольору мій користувацький UIView (colorThumb) приховується. Він стає видимим знову після закінчення анімації вибору / відміни, але це створює потворний артефакт.

Що мені робити, щоб це виправити? Чи не я вставляю підвід в потрібне місце?

(У didSelectRowAtIndexPath немає нічого особливого, я просто змінюю аксесуар комірки на прапорець або нічого і зніміть позначку з поточного indexPath).


Що таке upadteCell?
Ідан

updateCell робить деякі незначні зміни, наприклад встановлення галочки чи ні, вибираючи колір тексту залежно від доступності, ... але ніяких реальних змін, пов’язаних із самою коміркою або colorThumb.
Кирила

прийнята відповідь не забезпечує рішення, дивіться мою відповідь нижче для рішення
Павло Гуров

Відповіді:


227

UITableViewCellзмінює колір фону всіх уявлень підрозділів , коли обрана або виділена осередок, Ви можете вирішити цю проблему шляхом перевизначення Tableview клітина setSelected:animatedі setHighlighted: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)умови? Я думаю, що це спрацює, якщо у нас немає таких умов.
Рішаб Таял

@RishabhTayal в основному уникати перестановки змінної з однаковим значенням
cameloper

1
Зверніть увагу, що коли ви змінюєте колір тла під час вибору елемента, старий (неправильний) колір може бути відновлений, коли елемент не буде вибрано. Якщо це може статися, видаліть умови if (виділено) та якщо (вибрано).
Marcel W

Такий підхід скасовує анімацію, тому не має сенсу. Краще встановити стиль вибору комірок на .none.
Олександр Данилов

122

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


1
Дурний мене. Зрозуміло, що це було так, субперегляди повинні бути прозорими, щоб анімація відбору могла відбуватися належним чином. Дякую!
Кирила

52
Або ви можете знову встановити setHighlighted:animated:setSelected:animated:
переопределення

1
Якось скидання фонового кольору для мене не вийшло (працює на iOS 8.1). Натомість вирішив це, підкласифікувавши мій погляд і переосмисливши setBackgroundColor як [супер setBackgroundColor: [UIColor whiteColor]].
bizz84

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

@SimplGy Глибина виділення була б справді приємним варіантом, але ей - це UIKit, я бачив речі набагато гірші, ніж це =)
Павло Гуров

3
Працював для мене після того, як я змінив if на CGColorGetAlpha (backgroundColor! .CGColor) == 0, оскільки це не було рівним clearColor
piltdownman7

9

Іншим способом управління проблемою є заповнення подання градієнтом основної графіки, наприклад:

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

Гм, я намагаюся вказати цей точний код, і він взагалі не впливає на мене. Мій підпогляд - це UILabel, доданий як підпогляд cell.contentView та тестування під iOS 6.0.1, якщо це має значення.
Джо Строут

До чого ви застосовуєте код вище? А ви намагалися додати мітку просто до перегляду клітинки?
Агат

На мою думку це ідеальне рішення. Малювання до шару ідеально вирішує проблему, зберігаючи повну гнучкість. Мені не подобається рішення використання UIImageView, тому що тоді важче налаштувати градієнт або колір (вам доведеться створювати нове зображення кожного разу), а підкласифікація UIView саме для цього здається непосильною.
Ерік ван дер Нойт

@Lyida, я не дуже Swift-розробник. (Я ще більше C # -один). Але з того, що я бачив, це не зовсім специфічна мова, однак, в основному, логічна система какао / iOS Frameworks. Отже, ідея полягає у тому, щоб майже прозорий CAGradientLayer розмістити у вашому погляді, щоб отримати запитуваний результат.
Агат

9

Для Swift 2.2 це працює

cell.selectionStyle = UITableViewCellSelectionStyle.None

а причину пояснює @ Андрій

Це тому, що комірка подання таблиці автоматично змінює колір тла всіх переглядів всередині подання вмісту для виділеного стану.


8

Натхненний Yatheesha BL «s відповідь я створив UITableViewCell категорії / розширення , яке дозволяє включати і вимикати цю функцію прозорості" ".

Швидкий

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

Ціль-С

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;, а потім встановити фоновий колір у- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath


4

Натхненний Yatheesha BL .

Якщо ви зателефонуєте на super.setSelected (вибраний, анімований: анімований), він очистить усі встановлені кольори фону . Отже, ми не будемо називати супер метод.

У Свіфті:

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 Переосмислення зміненої і змінної методу - це різні речі. правильна відповідь - перекрити метод.
Numan Karaaslan

4

Це може бути випадок. Це розділи, щоб уникнути отримання сірого кольору для всіх елементів у комірці (якщо ви використовуєте власну комірку перегляду таблиці):

  1. Встановіть для виборуStyle значення .none 👉 selectionStyle = .none

  2. Перевизначте цей метод.

    func setHilirated (_ виділено: Bool, анімований: Bool)

  3. Зателефонуйте на супер, щоб отримати перевагу супер налаштування.

    super.setHighlight (виділено, анімовано: анімація)

  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

Це схоже на відповідь Павла Гурова, але більш гнучка тим, що дозволяє будь-якому кольору бути постійним.

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

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

0

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

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

Швидкий 4

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

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

-1

ось моє рішення, використовуйте contentView, щоб показати вибірColor, це працює ідеально

#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

Якщо згадане вище фонове рішення не вирішує вашу проблему, проблема може лежати у datasourceвашому таблиціView.

Для мене я створював екземпляр об’єкта DataSource (викликаний BoxDataSource) для обробки методів делегата та dataSource tableView таким чином:

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

Це спричинило переміщення джерела даних кожного разу при натисканні на клітинку, і таким чином весь вміст зник. Причиною цього є те, що ARC розмовляє / збирає сміття.

Щоб виправити це, мені довелося зайти в спеціальну клітинку, додати змінну джерела даних:

//CustomCell.swift
var dataSource: BoxDataSource?

Потім вам потрібно встановити джерело даних на джерело даних, що varви створили в CellForRow, так що це не буде розміщено з ARC.

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

Сподіваюся, що це допомагає.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.