Изменить фон ячейки UICollectionView при касании

У меня есть UICollectionView, который я создал программно. Я хотел бы, чтобы представление коллекции вело себя следующим образом:

1. User touches cell
2. Cell background color changes
3. User releases touch
4. Cell background color changes

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

Я рассматривал этот вопрос: ячейка UICollectionView меняет фон при нажатии

в котором есть следующее резюме методов, используемых для этой цели:

// Methods for notification of selection/deselection and highlight/unhighlight events.
// The sequence of calls leading to selection from a user touch is:
//
// (when the touch begins)
// 1. -collectionView:shouldHighlightItemAtIndexPath:
// 2. -collectionView:didHighlightItemAtIndexPath:
//
// (when the touch lifts)
// 3. -collectionView:shouldSelectItemAtIndexPath: or -    collectionView:shouldDeselectItemAtIndexPath:
// 4. -collectionView:didSelectItemAtIndexPath: or -collectionView:didDeselectItemAtIndexPath:
// 5. -collectionView:didUnhighlightItemAtIndexPath:

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

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
 {
   //pop vc 
 }

- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
  UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath];
  cell.contentView.backgroundColor = [UIColor redColor];
}

- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
  UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
  cell.contentView.backgroundColor = [UIColor greenColor];
}

Это приводит к изменению цвета фона ячейки только на красный. Я также рассмотрел этот вопрос: проблема с выбором и отменой выбора UICollectionView и попытался реализовать [UICollectionView selectItemAtIndexPath :animated:scrollPosition:] и вызывая его внутри didSelectItemAtIndexPath, но это тоже не сработало. Источник данных представления коллекции и делегат установлены.


comment
Проверьте мой ответ здесь: ‹stackoverflow.com/a/44112257/5416775› Это работает...!   -  person Abirami Bala    schedule 22.05.2017


Ответы (6)


Проблема в том, что вы меняете цвет при выделении и снова меняете его при отмене выделения, а не при отмене выделения.

Вы должны просто изменить это:

- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
  UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
  cell.contentView.backgroundColor = [UIColor greenColor];
}

к этому:

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

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

Изменить: также убедитесь, что вы звоните

[collectionView deselectItemAtIndexPath:indexPath animated:NO];

внутри метода -didSelectItemAtIndexPath

person Antonio E.    schedule 30.04.2014
comment
delaysContentTouches ‹--- Это!!! Нужна моя подсветка, чтобы по-прежнему работать по быстрому нажатию. Осмотрел все вокруг, не могу поверить, что это была одна маленькая собственность. Спасибо! - person bmjohns; 13.02.2015
comment
didUnhighlightItemAtIndexPath у меня вообще не работает. По каким причинам может не стрелять? - person zillaofthegods; 20.03.2015
comment
Вы установили делегата UICollectionView? - person Antonio E.; 23.03.2015
comment
У меня были проблемы с вызовом didUnhighlightItemAtIndexPath. Проблема была вызвана двумя причинами: 1. Если вы перезагрузите таблицу или отдельную ячейку во время didHighlight...(), выделение будет потеряно, и вы не получите выделение. 2. Если у вас есть другой распознаватель жестов, прикрепленный к collectionView, выделение будет потеряно после того, как оно сработает (у меня был LongPressGuestureRecognizer, и выделение было потеряно примерно через 0,5 секунды). - person ibuprofane; 18.10.2016

Версия Swift 3

Добавьте следующие два метода в свой класс контроллера представления:

// change background color when user touches cell
func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath)
    cell?.backgroundColor = UIColor.red
}

// change background color back when user releases touch
func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath)
    cell?.backgroundColor = UIColor.green
}

См. здесь помощь в настройке базового представления коллекции в Swift.

person Suragch    schedule 29.12.2015

Редактировать: ответ в Swift 3

var selectedIndex = Int ()

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell

    cell.backgroundColor = selectedIndex == indexPath.row ? UIColor.green : UIColor.red

    return cell
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
    selectedIndex = indexPath.row

    self.yourCollctionView.reloadData()
}
person Abirami Bala    schedule 22.05.2017
comment
зачем перезагружать всю коллекцию только для того, чтобы изменить цвет одной ячейки? - person smileBot; 09.11.2020

Вот мое решение. И я уверен, что это действительно работает.
Я предлагаю три метода выделения ячейки (selectedBackgroundView, оттенок cell.contentView и оттенок специальной области).

Как использовать:
1. просто унаследуйте BaseCollectionViewCell и ничего не делайте;
2. наследуйте и установите specialHighlightedArea = UIView() и contentView.addSubView(specialHighlightedArea), затем разместите их или добавьте ограничение для использования автоматического макета;
3. если вы этого не сделаете нужен эффект выделения, просто напишите метод с именем «shouldHighlightItemAtIndexPath», определенный UICollectionViewDelegate, и заставьте его возвращать false, или установите cell.shouldTintBackgroundWhenSelected = false и установите specialHighlightedArea = nil и удалите его из superView.

/// same with UITableViewCell's selected backgroundColor
private let highlightedColor = UIColor(rgb: 0xD8D8D8) 

/// you can make all your collectionViewCell inherit BaseCollectionViewCell
class BaseCollectionViewCell: UICollectionViewCell {

    /// change it as you wish when or after initializing
    var shouldTintBackgroundWhenSelected = true

    /// you can give a special view when selected
    var specialHighlightedArea: UIView? 

    // make lightgray background display immediately(使灰背景立即出现)
    override var isHighlighted: Bool { 
        willSet {
            onSelected(newValue)
        }
    }

    // keep lightGray background until unselected (保留灰背景)
    override var isSelected: Bool { 
        willSet {
            onSelected(newValue)
        }
    }

    func onSelected(_ newValue: Bool) {
        guard selectedBackgroundView == nil else { return }
        if shouldTintBackgroundWhenSelected {
            contentView.backgroundColor = newValue ? highlightedColor : UIColor.clear
        }
        if let area = specialHighlightedArea {
            area.backgroundColor = newValue ? UIColor.black.withAlphaComponent(0.4) : UIColor.clear
        }
    }
}

extension UIColor {
    convenience init(rgb: Int, alpha: CGFloat = 1.0) {
        self.init(red: CGFloat((rgb & 0xFF0000) >> 16) / 255.0, green: CGFloat((rgb & 0xFF00) >> 8) / 255.0, blue: CGFloat(rgb & 0xFF) / 255.0, alpha: alpha)
    }
}
person DawnSong    schedule 20.10.2016
comment
разве specialHighlightedArea не должен быть слабым? - person Samer Murad; 29.01.2017
comment
@SamerMurad При использовании xib/storyboard вы можете использовать weak. - person DawnSong; 06.02.2017
comment
Действительно? Я почти уверен, что это не имеет ничего общего с xib/раскадровкой. Я имею в виду, что пользовательский интерфейс уже содержит UIView, поэтому на самом деле нет необходимости в строгой ссылке, не так ли? - person Samer Murad; 06.02.2017

Простое бинарное логическое решение. Работает со Swift 3 и 4:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt
    indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath) as! CategoryCell
    let lastCellColor = cell.backgroundColor
    if cell.isSelected {cell.backgroundColor = .green} else {cell.backgroundColor = lastCellColor}
}
person Brian    schedule 16.12.2018

Добавьте все подпредставления внутрь contentView, используйте backgroundView и selectedBackgroundView из UICollectionViewCell. Не устанавливайте contentView.backgroundColor.

// Add this inside your cell configuration.
private func setupSelectionColor() {
    let backgroundView = UIView()
    backgroundView.backgroundColor = .white
    self.backgroundView = backgroundView

    let selectedBackgroundView = UIView()
    selectedBackgroundView.backgroundColor = .orange
    self.selectedBackgroundView = selectedBackgroundView
}

// Add the deselection inside didSelectCallback
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    collectionView.deselectItem(at: indexPath, animated: true)
}
person Mihai Georgescu    schedule 20.05.2020