UICollectionView单元选择和单元重用

Pad*_*215 48 objective-c ios uicollectionview

选择单元格后,我想处理更改单元格外观.我想委托方法collectionView:didSelectItemAtIndexPath:&collectionView:didDeselectItemAtIndexPath:是我应该编辑细胞.

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

    DatasetCell *datasetCell = 
      (DatasetCell *)[collectionView cellForItemAtIndexPath:indexPath];

    [datasetCell replaceHeaderGradientWith:[UIColor skyBlueHeaderGradient]];
    datasetCell.backgroundColor = [UIColor skyBlueColor];
}
Run Code Online (Sandbox Code Playgroud)

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

    DatasetCell *datasetCell = 
      (DatasetCell *)[collectionView cellForItemAtIndexPath:indexPath];

    [datasetCell replaceHeaderGradientWith:[UIColor grayGradient]];
    datasetCell.backgroundColor = [UIColor myDarkGrayColor];
}
Run Code Online (Sandbox Code Playgroud)

这种方法很好,除非重用单元格.如果我在索引(0,0)处选择单元格,它会更改外观,但是当我向下滚动时,会有另一个单元格处于选定状态.

我相信我应该使用这种UICollectionViewCell方法-(void)prepareForReuse来准备细胞以便重复使用(即,将细胞外观设置为非选择状态),但它给我带来了困难.

-(void)prepareForReuse {
    if ( self.selected ) {
        [self replaceHeaderGradientWith:[UIColor skyBlueHeaderGradient]];
        self.backgroundColor = [UIColor skyBlueColor];
    } else {
        [self replaceHeaderGradientWith:[UIColor grayGradient]];
        self.backgroundColor = [UIColor myDarkGrayColor];
    }
}
Run Code Online (Sandbox Code Playgroud)

当我向后滚动到顶部时,索引(0,0)处的单元格处于取消选择状态.

当我刚刚使用cell.backgroundView属性时,为了防止这种情况发生在:

-(void)prepareForReuse {
    self.selected = FALSE;
}
Run Code Online (Sandbox Code Playgroud)

并且选择状态按预期工作.

有任何想法吗?

Ani*_*ese 73

你的观察是正确的.由于重用单元格,这种情况正在发生.但是你不必对prepareForReuse做任何事情 .而是检查cellForItem并相应地设置属性.就像是..

 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cvCell" forIndexPath:indexPath];


if (cell.selected) {
     cell.backgroundColor = [UIColor blueColor]; // highlight selection 
}
else
{
     cell.backgroundColor = [UIColor redColor]; // Default color
}
return cell;
}

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

    UICollectionViewCell *datasetCell =[collectionView cellForItemAtIndexPath:indexPath];
    datasetCell.backgroundColor = [UIColor blueColor]; // highlight selection
 }  

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

UICollectionViewCell *datasetCell =[collectionView cellForItemAtIndexPath:indexPath]; 
datasetCell.backgroundColor = [UIColor redColor]; // Default color
}
Run Code Online (Sandbox Code Playgroud)

  • 选定的单元格图像更改,但滚动时选择更改. (2认同)

ste*_*anB 24

框架将处理切换为您的意见,一旦你设置你的细胞的backgroundViewselectedBackgroundView,看到例如管理用于选择和突出了视觉状态:

UIView* backgroundView = [[UIView alloc] initWithFrame:self.bounds];
backgroundView.backgroundColor = [UIColor redColor];
self.backgroundView = backgroundView;

UIView* selectedBGView = [[UIView alloc] initWithFrame:self.bounds];
selectedBGView.backgroundColor = [UIColor whiteColor];
self.selectedBackgroundView = selectedBGView;
Run Code Online (Sandbox Code Playgroud)

您只需要在您的类中实现UICollectionViewDelegate启用单元格以突出显示并选择如下:

- (BOOL)collectionView:(UICollectionView *)collectionView
        shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}

- (BOOL)collectionView:(UICollectionView *)collectionView
        shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath;
{
    return YES;
}
Run Code Online (Sandbox Code Playgroud)

这对我有用.

  • 这两个方法(shouldHighlightItemAtIndexPath/shouldSelectItemAtIndexPath)都在UICollectionViewDelegate而不是数据源 (6认同)

Ale*_*lko 21

UICollectionView在iOS 10中发生了变化,为上述解决方案带来了一些问题.

这是一个很好的指南:https: //littlebitesofcocoa.com/241-uicollectionview-cell-pre-fetching

离开屏幕后,细胞现在可以保持一段时间.这意味着有时我们可能无法控制单元格didDeselectItemAt indexPath来调整它.然后它可以在屏幕上显示未更新和未回收.prepareForReuse没有帮助这个角落的情况.

最简单的解决方案是通过设置isPrefetchingEnabled为false 来禁用新滚动.有了这个,cellForItemAt didSelect didDeselect用以前的工作管理单元格的显示 .

但是,如果你想保持新的平滑滚动行为,最好使用willDisplay:

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    let customCell = cell as! CustomCell
    if customCell.isSelected {
        customCell.select()
    } else {
        customCell.unselect()
    }
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
    //Don't even need to set selection-specific things here as recycled cells will also go through willDisplay
    return cell
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath) as? CustomCell
    cell?.select()
}

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath) as? CustomCell
    cell?.unselect() // <----- this can be null here, and the cell can still come back on screen!
}
Run Code Online (Sandbox Code Playgroud)

通过上述操作,您可以在选择单元格时控制单元格,在屏幕上取消选择,回收并重新显示.


Pad*_*215 10

Anil走在正确的轨道上(他的解决方案看起来应该可行,我开发了独立于他的解决方案).我仍用prepareForReuse:的方法来设置单元格的selectedFALSE,然后在cellForItemAtIndexPath我检查,看是否细胞的指数是在'collectionView.indexPathsForSelectedItems',如果是的话,选中它.

在自定义单元格中:

-(void)prepareForReuse {
    self.selected = FALSE;
}
Run Code Online (Sandbox Code Playgroud)

cellForItemAtIndexPath:处理突出显示和dehighlighting重用单元格时:

if ([collectionView.indexPathsForSelectedItems containsObject:indexPath]) {
    [collectionView selectItemAtIndexPath:indexPath animated:FALSE scrollPosition:UICollectionViewScrollPositionNone];
    // Select Cell
}
else {
    // Set cell to non-highlight
}
Run Code Online (Sandbox Code Playgroud)

然后在didDeselectItemAtIndexPath:和中处理单元格突出显示和取消高亮显示didSelectItemAtIndexPath:

这对我来说就像一个魅力.

  • 不要忘记准备重用的超级电话! (2认同)

ano*_*eal 6

我有一个水平滚动集合视图(我在Tableview中使用集合视图),我也遇到了单元重用的问题,每当我选择一个项目并向右滚动时,下一个可见集合中的一些其他单元格会自动选择.尝试使用任何自定义单元格属性,如"选定",突出显示等解决此问题并没有帮助我,所以我提出了以下解决方案,这对我有用.

步骤1:

在collectionView中创建一个变量来存储选定的索引,这里我使用了一个名为selectedIndex的类级变量

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

{

    MyCVCell *cell = (MyCVCell*)[collectionView dequeueReusableCellWithReuseIdentifier:@"MyCVCell" forIndexPath:indexPath];    

// When scrolling happens, set the selection status only if the index matches the selected Index

if (selectedIndex == indexPath.row) {

        cell.layer.borderWidth = 1.0;

        cell.layer.borderColor = [[UIColor redColor] CGColor];

    }
    else
    {
        // Turn off the selection
        cell.layer.borderWidth = 0.0;

    }
    return cell;

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

{
    MyCVCell *cell = (MyCVCell *)[collectionView cellForItemAtIndexPath:indexPath];
    // Set the index once user taps on a cell
    selectedIndex = indexPath.row;
    // Set the selection here so that selection of cell is shown to ur user immediately
    cell.layer.borderWidth = 1.0;
    cell.layer.borderColor = [[UIColor redColor] CGColor];
    [cell setNeedsDisplay];
}

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

{

    MyCVCell *cell = (MyCVCell *)[collectionView cellForItemAtIndexPath:indexPath];

    // Set the index to an invalid value so that the cells get deselected
    selectedIndex = -1;
    cell.layer.borderWidth = 0.0;
    [cell setNeedsDisplay];

}
Run Code Online (Sandbox Code Playgroud)

-anoop