Подтвердить что ты не робот

Где выделить UICollectionViewCell: делегат или ячейка?

В соответствии с Руководство по программированию в формате Collection необходимо обработать визуальное состояние подсветки ячейки в UICollectionViewDelegate. Вот так:

- (void)collectionView:(PSUICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    MYCollectionViewCell *cell = (MYCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
    [cell highlight];
}

- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    MYCollectionViewCell *cell = (MYCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
    [cell unhighlight];
}

Что мне не нравится в этом подходе, так это то, что он добавляет логику к делегату, который очень специфичен для ячейки. Фактически, UICollectionViewCell управляет своим выделенным состоянием независимо через свойство highlighted.

Не будет ли переопределение setHighlighted: более чистым решением, тогда?

- (void)setHighlighted:(BOOL)highlighted
{
    [super setHighlighted:highlighted];
    if (highlighted) {
        [self highlight];
    } else {
        [self unhighlight];
    }
}

Есть ли недостатки для этого подхода, а не для подхода делегата?

4b9b3361

Ответ 1

Как говорится в документации, вы можете полагаться на свойство highlighted, которое нужно изменить, пока ячейка подсвечивается. Например, следующий код сделает ячейку красной, если она выделена (но не ее подпункты):

- (void)setHighlighted:(BOOL)highlighted {
    [super setHighlighted:highlighted];
    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];

    if (self.highlighted) {
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetRGBFillColor(context, 1, 0, 0, 1);
        CGContextFillRect(context, self.bounds);
    } 
}

И если вы добавите что-то вроде этого, фон станет фиолетовым (красный + непрозрачный синий):

- (void)collectionView:(UICollectionView *)colView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [colView cellForItemAtIndexPath:indexPath];
    cell.contentView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.5];
}

- (void)collectionView:(UICollectionView *)colView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [colView cellForItemAtIndexPath:indexPath];
    cell.contentView.backgroundColor = nil;
}

Таким образом, вы можете использовать обе вместе (не обязательно меняя внешний вид ячейки). Разница в том, что с помощью методов делегатов у вас также есть indexPath. Он может использоваться для создания множественного выбора (вы будете использовать эти методы вместе с методами делегата выбора), чтобы показать предварительный просмотр, пока ячейка подсвечена, чтобы показать некоторую анимацию с другими представлениями... Для этого делегата существует довольно много устройств методы, на мой взгляд.

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

Ответ 2

Ниже приведены два возможных подхода.

Подклассы ячеек

Более чистый подход, если он уже подклассифицирован из UICollectionViewCell.

class CollectionViewCell: UICollectionViewCell {

    override var highlighted: Bool {
        didSet {
            self.contentView.backgroundColor = highlighted ? UIColor(white: 217.0/255.0, alpha: 1.0) : nil
        }
    }
}

UICollectionViewDelegate

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

func collectionView(collectionView: UICollectionView, didHighlightItemAtIndexPath indexPath: NSIndexPath) {

    if let cell = collectionView.cellForItemAtIndexPath(indexPath) {
        cell.contentView.backgroundColor = UIColor(white: 217.0/255.0, alpha: 1.0) // Apple default cell highlight color
    }
}


func collectionView(collectionView: UICollectionView, didUnhighlightItemAtIndexPath indexPath: NSIndexPath) {

    if let cell = collectionView.cellForItemAtIndexPath(indexPath) {
        cell.contentView.backgroundColor = nil
    }
}

Ответ 3

Ну... как все эти методы верны. Я нашел способ, который кажется самым легким для меня. Просто переопределите метод setSelected: (например, чтобы изменить цвет фона):

-(void)setSelected:(BOOL)selected{
    self.backgroundColor = selected?[UIColor greenColor]:[UIColor grayColor];
    [super setSelected:selected];
}

... он работает "из коробки" (даже с помощью коллекцииView.allowsMultipleSelection)

Ответ 4

Обратите внимание, что UICollectionViewCell имеет свойство selectedBackgroundView. По умолчанию он равен нулю. Просто создайте представление для этого свойства, и оно появится, когда пользователь коснется ячейки.

override func awakeFromNib() {
    super.awakeFromNib()

    let view = UIView(frame: contentView.bounds)
    view.isUserInteractionEnabled = false
    view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    view.backgroundColor = UIColor(white: 0.94, alpha: 1.0)
    selectedBackgroundView = view
}

Ответ 5

Как взято непосредственно из UICollectionViewCell.h - правильное переопределение как setSelected, так и setHighlighted. В зависимости от вашей ситуации вы можете рассмотреть возможность назначения пользовательских представлений backgroundView и selectedBackgroundView, которые автоматически меняются при выборе.

// Cells become highlighted when the user touches them.
// The selected state is toggled when the user lifts up from a highlighted cell.
// Override these methods to provide custom UI for a selected or highlighted state.
// The collection view may call the setters inside an animation block.
@property (nonatomic, getter=isSelected) BOOL selected;
@property (nonatomic, getter=isHighlighted) BOOL highlighted;

// The background view is a subview behind all other views.
// If selectedBackgroundView is different than backgroundView, it will be placed above the background view and animated in on selection.
@property (nonatomic, retain) UIView *backgroundView;
@property (nonatomic, retain) UIView *selectedBackgroundView;

Ответ 6

Swift 3: (основываясь на ответе A-Live)

import UIKit

class MyCollectionViewCell: UICollectionViewCell {

    override var highlighted: Bool {
        didSet {
            self.setNeedsDisplay()
        }
    }

    override func drawRect(rect: CGRect) {
        super.drawRect(rect)
        myImageView.highlighted = self.highlighted
    }
}

Swift 4

import UIKit

class MyCollectionViewCell: UICollectionViewCell {

    override var isHighlighted: Bool {
        didSet {
            self.setNeedsDisplay()
        }
    }

    override func draw(_ rect: CGRect) {
        super.draw(rect)
        myImageView.isHighlighted = self.isHighlighted
    }
}

Ответ 7

Достаточно для подсветки ячейки (Swift 4)

class MyCollectionViewCell: UICollectionViewCell {
...
    override var isHighlighted: Bool {
        didSet {
            if isHighlighted {
                self.contentView.alpha = 0.6
            }
            else {
                self.contentView.alpha = 1.0
            }
        }
    }
}