UICollectionView - didDeselectItemAtIndexPath не вызывается, если выбрана ячейка
Первое, что я делаю, это устанавливаю выбранную ячейку.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
cell.selected = YES;
return cell;
}
И ячейка удачно выбрана. Если пользователь касается выбранной ячейки, то эта ячейка должна быть отменена, и делегаты должны быть вызваны. Но этого никогда не случится.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"%s", __PRETTY_FUNCTION__);
}
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"%s", __PRETTY_FUNCTION__);
}
Я знаю, что делегатов не вызывают, если я устанавливаю выбор программно. Делегат и источник данных установлены.
Тем не менее, этот делегат вызывается:
- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"%s", __PRETTY_FUNCTION__);
return YES;
}
Если я удалю cell.selected = YES
чем все работает. Есть ли кто-нибудь, кто может мне объяснить это поведение?
8 ответов
Проблема в том, что ячейка выбрана, но UICollectionView
ничего не знает об этом. Дополнительный звонок для UICollectionView
решает проблему:
[collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
Полный код:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
cell.selected = YES;
[collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
return cell;
}
Я держу вопрос, чтобы помочь кому-то, кто может столкнуться с той же проблемой.
Я думаю, что решение @zeiteisen - это обходной путь. Реальная вещь лежит в режиме выбора. Там нет ничего, чтобы установить в свойстве cell.selected
,
Есть два свойства UICollectionView
название allowsMultipleSelection
а также allowsSelection
,
allowsMultipleSelection
является NO
по умолчанию и allowsSelection
является YES
,
Если вы хотите выбрать только одну ячейку, то код @ инициализация выглядит так
yourCollectionView.allowsMultipleSelection = NO;
yourCollectionView.allowsSelection = YES; //this is set by default
Тогда настройки позволят вам выбрать только одну ячейку за раз, не меньше и не больше. Вы должны выбрать хотя бы одну ячейку. didDeselectItemAtIndexPath
не будет вызван, если вы не выберете другую ячейку. Нажав на уже выбранный UICollectionViewCell
не сделает это, чтобы отменить выбор. Это политика реализации.
Если вы хотите выбрать несколько ячеек, то код @ инициализация должен выглядеть следующим образом:
yourCollectionView.allowsMultipleSelection = YES;
yourCollectionView.allowsSelection = YES; //this is set by default
Тогда настройки позволят выбрать несколько ячеек. Эти настройки позволяют ни один или несколько UICollectionViewCell
быть выбранным. Номер выбранной ячейки будет
0 <= number_selected_cell <= total_number_of_cell
Это политика выбора нескольких ячеек.
Если вы намереваетесь использовать что-либо из вышеперечисленного, вы можете использовать яблочный API без дополнительной головной боли, в противном случае вам нужно найти способ проникнуть в вашу цель, используя свой собственный код или яблочный API.
Я была такая же проблема. Я предварительно выбрал ячейки при загрузке таблицы, но мне пришлось дважды нажать ячейку, чтобы отменить ее выбор. Ответ @zeiteisen помог мне. Тем не менее, я работаю в Swift 3, поэтому я решил дать ответ в Swift.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
if /*Test for Selection*/ {
cell.isSelected = true
collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .left)
}
return cell
}
У меня была такая же проблема, если вы исследуете дальше, вы увидите, что не только дидиселект не вызывается, но и само прикосновение не воспринимается клеткой. Для меня было решено разрешить асинхронное выполнение выбора и установить selecItem вручную. Внутри cellForItemAt.
DispatchQueue.main.async {
cell.isSelected = true
collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .init())
}
Используйте.init() и false для анимации, если вы не хотите видеть движения. Если вы не заключите это в блок async, вы увидите, как пользовательский интерфейс прыгает при прокрутке.
Добавьте эту строку в ваш метод didSelectItemAtIndexPath
[collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:nil]
В моем случае я хочу изменить фон кнопки, другими словами фон ячейки в представлении коллекции:
class CustomCVCell: UICollectionViewCell {
override var isSelected: Bool {
didSet {
grayBackgroundViewWithImage.image =
isSelected ? UIImage(named: "") : UIImage()
}
}
В основном классе, где хранится представление коллекции, создайте эту переменную:
class CustomViewController: UIViewController {
///save the indexPath of last selected cell
private var lastSelectedIndexPath: IndexPath? }
В viewDidLoad () установите это значение в false:
customCollectionView.allowsMultipleSelection = false
Дальнейший код в источнике данных. В моем случае должна быть выбрана первая ячейка:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CustomCVCell.cellID(),
for: indexPath) as! CustomCVCell
if indexPath.row == 0 {
lastSelectedIndexPath = indexPath
cell.isSelected = true
}
//update last select state from lastSelectedIndexPath
cell.isSelected = (lastSelectedIndexPath == indexPath)
return cell
}
Дальнейший код в делегате:
///UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard lastSelectedIndexPath != indexPath else { return }
if let index = lastSelectedIndexPath {
let cell = collectionView.cellForItem(at: index) as! CustomCVCell
cell.isSelected = false
}
let cell = collectionView.cellForItem(at: indexPath) as! CustomCVCell
cell.isSelected = true
lastSelectedIndexPath = indexPath
}
В моем случае это было вызвано использованием той же логики для
func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool
что касается
func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool
И когда ячейка была выбрана, должен HighlightItemAt возвращал false - и это не позволило мне отменить выбор этой ячейки.
Надеюсь, это сэкономит кому-то время:)
Перезагрузка камеры была решением для меня. Что мне нужно, так это кратковременное изменение изображения в камере. Я назначаю изображение для imageView в cellForItemAtIndexPath, и когда пользователь касается ячейки, я меняю изображение и запускаю mycode, затем перезагружаю ячейку.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath) as! MenuCollectionViewCell
cell.backgroundImageView.image = UIImage(named: "selected")
// handle tap events
collectionView.reloadItemsAtIndexPaths([indexPath])
}
Надеюсь, это поможет кому-то.