Где выделить 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];
}
}
Есть ли недостатки для этого подхода, а не для подхода делегата?
Ответы
Ответ 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
}
}
}
}