it-swarm.com.ru

Изменить фон ячейки 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, но это тоже не сработало. Сбор данных представления источника и делегата задан.

27
jac300

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

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

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

45
Antonio E.

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.

29
Suragch

Правка: ответ в 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()
}
5
Abirami Bala

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

Как пользоваться:
1. просто наследуй BaseCollectionViewCell и ничего не делай;
2. наследовать и устанавливать specialHighlightedArea = UIView() и contentView.addSubView(specialHighlightedArea), затем компоновать его или добавлять ограничение для использования Auto Layout;
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)
    }
}
4
DawnSong

Простое бинарное логическое решение. Работает со 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}
}
0
Brian