Повторное использование ячеек UICollectionView — некоторые ячейки не выбираются

В UICollectionView у меня есть пользовательский UICollectionViewCellClass, где prepareForReuse переопределяется для форматирования по умолчанию.

У меня есть NSMutableArray, содержащий NSIndexPaths из didSelectItemAtIndexPath:.

В cellForItemAtIndexPath: я переформатирую выделенные ячейки, чтобы они выглядели выделенными.

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{

ButtonCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ButtonCell" forIndexPath:indexPath];

NSString *title = self.ingredientsBook.names[indexPath.item];

cell.label.text = title;

if ([self isSelectedIndexPath:indexPath]){

    cell.backgroundColor = [UIColor whiteColor];
    cell.label.textColor = [UIColor blueColor];
}
return cell;

}

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{

self.searchButton.enabled = YES;

ButtonCell *cell = (ButtonCell *)[collectionView cellForItemAtIndexPath:indexPath];
[selectedCellIndexPaths addObject:indexPath];
NSLog(@"%@", selectedCellIndexPaths);
cell.backgroundColor = [UIColor whiteColor];
cell.label.textColor = [UIColor blueColor];

NSString *name = self.ingredientsBook.names[indexPath.item];
[self.selectedIngredientNames addObject:name];


}

Проблема в том, что когда я нажимаю на первую ячейку, невозможно выбрать 16-ю или 17-ю. Или, если я нажму на первые три, невозможно выбрать три последних. Я полагаю, что didSelectItemAtIndexPath не вызывается.

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

Я попытался поставить NSLogsв shouldSelectItemAtIndexPath, чтобы понять, вызывался ли этот метод, и метод вообще не вызывается. Это происходит, когда между выбранным и проблемным находится расстояние в 16 ячеек.

Вот другие методы источника данных и isSelectedIndexPath:

-(BOOL)isSelectedIndexPath:(NSIndexPath *)indexPath{

for (NSIndexPath *test in selectedCellIndexPaths){
    if (test == indexPath){
        return YES;
    }
}

return NO;
}

-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{

return [self.ingredientsBook.names count];
}

-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{

return 1;
}

-(BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath{

NSLog(@"%@", indexPath);

return YES;
}


-(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath{

self.searchButton.enabled = ([[collectionView indexPathsForSelectedItems] count] > 0);

ButtonCell *cell = (ButtonCell *)[collectionView cellForItemAtIndexPath:indexPath];
cell.backgroundColor = [UIColor blackColor];
cell.label.textColor = [UIColor whiteColor];

[selectedCellIndexPaths removeObject:indexPath];
NSString *name = self.ingredientsBook.names[indexPath.item];
[self.selectedIngredientNames removeObject:name];



}

person ragnarok    schedule 06.04.2013    source источник
comment
Что такое isSelectedIndexPath? Где вы это создаете? Я думаю, вам также нужна часть else, чтобы сказать, как должны выглядеть ячейки, если [self isSelectedIndexPath:indexPath] возвращает false.   -  person rdelmar    schedule 06.04.2013
comment
это метод, который проверяет, содержится ли indexPath в NSMutableArray NSIndexPaths. он всегда возвращает false, если indexPath равен одному из выбранных в массиве.   -  person ragnarok    schedule 06.04.2013
comment
Хорошо, вы добавили часть else в оператор if, чтобы посмотреть, поможет ли это. Из-за повторного использования ячеек вам необходимо установить внешний вид ячейки в невыбранное состояние, если это утверждение if ложно.   -  person rdelmar    schedule 06.04.2013
comment
Я не могу объяснить каждую 16-ю ячейку, не видя больше кода. Я не вижу ничего в том, что вы написали, что объясняло бы это. Вы должны опубликовать все методы источника данных и метод isSelectedIndexPath:.   -  person rdelmar    schedule 06.04.2013
comment
я попытался добавить часть else, но, похоже, это не повлияло на это. когда я регистрирую shouldSelectItemAtIndexPath: я не получаю ответа. как будто метод не был вызван. но я нажимаю на эту ячейку! это безумие   -  person ragnarok    schedule 06.04.2013
comment
я постараюсь выложить весь проект   -  person ragnarok    schedule 06.04.2013
comment
вот весь проект github.com/aluphedrion/Tomatto   -  person ragnarok    schedule 06.04.2013
comment
Что мне нужно сделать, чтобы проверить вашу ошибку? Я вижу только 6 ячеек, поэтому я не могу добраться до 16 или 17.   -  person rdelmar    schedule 06.04.2013
comment
извините, это не было обновлено, проверьте еще раз репозиторий git   -  person ragnarok    schedule 06.04.2013


Ответы (3)


Я нашел две проблемы. Метод prepareForReuse, похоже, все испортил, поэтому я просто удалил его. Однако основная проблема заключалась в том, как вы реализовали isSelectedIndexPath:. Как только он находит первый выбранный элемент в цикле по элементам, он возвращает YES и выходит из цикла. Что вы хотите сделать, это просто проверить, содержится ли indexPath в массиве selectedCellIndexPaths:

-(BOOL)isSelectedIndexPath:(NSIndexPath *)indexPath{

    if ([selectedCellIndexPaths containsObject:indexPath]) {
        return YES;
    }else{
        return NO;
    }
}

Или, если вы предпочитаете использовать более краткий синтаксис, вы можете заменить блок if-else на:

return  ([selectedCellIndexPaths containsObject:indexPath])? YES : NO;
person rdelmar    schedule 06.04.2013
comment
даже с этими изменениями проблема сохраняется. однако большое спасибо за ваше терпение и настойчивость. - person ragnarok; 07.04.2013
comment
извините, я скучаю по удалению prepareForReuse. Теперь все работает блестяще. Большое спасибо за терпение и настойчивость еще раз. - person ragnarok; 07.04.2013
comment
Только 1_ - person k06a; 02.10.2013

Недавно я столкнулся с точно такой же проблемой с моим приложением. Выбор UICollectionViewCell работал правильно до iOS 8.3, впоследствии я начал замечать странное поведение. Ячейки, которые на самом деле не были выбраны, будут казаться выбранными, другие ячейки, казалось бы, случайным образом, не могут быть выбраны.

У меня были пользовательские методы setSelected и prepareForResuse, реализованные в подклассе UICollectionViewCell как таковые:

 -(void)setSelected:(BOOL)selected
{
     [super setSelected:selected];

    if (selected)
    {
        [[self selectedIndicator] setHidden:NO];
    }
    else
    {
        [[self selectedIndicator] setHidden:YES];
    }
}

-(void)prepareForReuse
{
    [[self imageView] setImage:nil];
}

Метод prepareForReuse просто сбрасывает представление изображения в пользовательской ячейке.

В моем методе prepareForReuse я не вызывал [super prepareForReuse] (который по документации ничего не делает по умолчанию). Когда я добавил вызов к [super prepareForReuse], все выделение работало как задумано. Хотя Apple заявляет, что реализация по умолчанию ничего не делает, они также рекомендуют вызывать super. Следование этой рекомендации решило мою проблему.

person user3847320    schedule 26.06.2015

В iOS 10 я обнаружил, что программная очистка UICollectionView с включенным множественным выбором приводила к ошибкам при включенной предварительной выборке. И, конечно же, предварительная выборка включена по умолчанию в iOS 10.

person xaphod    schedule 17.11.2016