UICollectionView - 如果选择了单元格,则不调用didDeselectItemAtIndexPath

时间:2013-12-04 16:21:12

标签: ios objective-c uicollectionview

我要做的第一件事是设置选定的单元格。

- (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 个答案:

答案 0 :(得分:56)

问题是,单元格已被选中,但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;
}

我保留这个问题,以帮助可能面临同样问题的人。

答案 1 :(得分:23)

我认为@zeiteisen提供的解决方案是一种解决方案。实际的事情在于选择模式。属性cell.selected中没有设置任何内容。

UICollectionView名称allowsMultipleSelectionallowsSelection有两个属性。

默认情况下,

allowsMultipleSelectionNOallowsSelectionYES

如果您只想选择一个单元格,那么代码@the初始化看起来像

yourCollectionView.allowsMultipleSelection = NO;
yourCollectionView.allowsSelection = YES; //this is set by default

然后,设置将允许您一次只选择一个单元格,而不是更少。 您必须至少选择一个单元格。除非您选择其他单元格,否则不会调用didDeselectItemAtIndexPath。点击已选择的UICollectionViewCell赢得了取消选择。这是实施背后的政策。

如果要选择多个单元格,则代码@the初始化应如下所示:

yourCollectionView.allowsMultipleSelection = YES;
yourCollectionView.allowsSelection = YES; //this is set by default

然后设置将允许选择多个单元格。此设置不允许选择任何一个或多个UICollectionViewCell。选择的单元格数为

0 <= number_selected_cell <= total_number_of_cell

这是多小区选择背后的政策。

如果您打算使用上述任何一种,欢迎使用苹果api而不会让您头疼,否则您必须找到一种方法,使用您自己的代码或苹果的API来潜入您的目标。< / p>

答案 2 :(得分:6)

我有同样的问题。我在桌面加载时预先选择了单元格但我不得不双击一个单元格以取消选择它。 @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
}

答案 3 :(得分:1)

将此行添加到didSelectItemAtIndexPath方法

[collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:nil]

答案 4 :(得分:1)

就我而言,我想更改按钮的背景,即集合视图中单元格的背景:

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
}

enter image description here enter image description here enter image description here enter image description here

答案 5 :(得分:0)

重新加载细胞对我来说是解决方案。我需要的是在短时间内改变单元格中的图像。我将图像分配给cellForItemAtIndexPath中的imageView,当用户触摸单元格时,我更改图像并运行mycode,然后重新加载单元格。

record = AccountTransaction.create
record.update(original: record)

希望它有所帮助。

答案 6 :(得分:0)

在我的情况下,这是由于使用相同的逻辑导致的

func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool

func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool

并且当选择了单元格时,应该HighHighItemAt返回false-这阻止了我取消选择该单元格。

希望这可以节省别人的时间:)

答案 7 :(得分:0)

我遇到了同样的问题,如果您进一步调查,您会发现不仅没有调用diddiselect,而且单元本身也没有感觉到触摸。对我来说解决的是允许异步执行选择并手动设置selecItem。 在cellForItemAt内部。

       DispatchQueue.main.async {
            cell.isSelected = true
            collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .init())
        }

如果不想看到运动,请在动画上使用.init()和false。如果不使用异步块包装它,则滚动时会看到UI跳动。