UICollectionView - 如果选择了单元格,则不调用 didDeselectItemAtIndexPath
Posted
技术标签:
【中文标题】UICollectionView - 如果选择了单元格,则不调用 didDeselectItemAtIndexPath【英文标题】:UICollectionView - didDeselectItemAtIndexPath not called if cell is selected 【发布时间】:2013-12-04 16:21:12 【问题描述】:我要做的第一件事是设置选中的单元格。
- (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
,那么一切正常。有没有人可以解释这种行为?
【问题讨论】:
当您使用 cellforItemAtIndexPath 时,它会为 tableview 中的每个单元格调用,所以基本上您正在尝试设置每个选定的单元格。你想达到什么目的? 【参考方案1】:问题是,该单元格已被选中,但 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。在我的情况下,当我选择一个单元格didSelectItemAtIndexPath
时被调用,但是当第二次单击单元格时它不会调用didDselectItemAtIndexPath
。我想在这两种方法中更改单元格的内容。我该怎么做?
它有效,但我还需要理解为什么需要它:集合视图回调说用户选择了单元格->我要求它重新加载单元格,以便我可以直观地反映更改,那么当它询问单元格时,我需要告诉它(再次)选择它吗?【参考方案2】:
我认为@zeiteisen 提供的解决方案是一种解决方案。实际的事情在于选择模式。在属性cell.selected
中无需设置任何内容。
UICollectionView
名称 allowsMultipleSelection
和 allowsSelection
有两个属性。
allowsMultipleSelection
默认为NO
,allowsSelection
为YES
。
如果你只想选择一个单元格,那么代码@初始化看起来像
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
这是多个单元格选择背后的策略。
如果您打算使用上述任何一种方法,欢迎您使用 apples api 而不会额外感到头疼,否则您必须找到一种方法来使用您自己的代码或 apple 的 api 潜入您的目标。
【讨论】:
你是对的,简单地说:如果用户再次点击它,集合视图不会自动取消选择已选择的单元格。 allowMultipleSelection 属性文档中的说明是错误的。对我来说,苹果这样实现它是很奇怪的,为了实现“再次点击并取消选择”行为,我们应该自己维护一个选择标志。 这应该被选为正确答案。关键是设置allowMultipleSelection=YES。 我遇到了@Chris 提到的问题。显然这是因为在我的自定义 collectionView 单元格中覆盖了 setIsSelected 而没有调用 super.选择和取消选择按照文档中的说明进行。【参考方案3】:我有同样的问题。我在表格加载时预先选择了单元格,但我不得不双击一个单元格来取消选择它。 @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
【讨论】:
【参考方案4】:将此行添加到您的 didSelectItemAtIndexPath 方法中
[collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:nil]
【讨论】:
【参考方案5】:在我的例子中,我想改变按钮的背景,换句话说就是集合视图中单元格的背景:
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
【讨论】:
【参考方案6】:重新加载单元格对我来说是解决方案。我需要的是在单元格中更改图像片刻。我将图像分配给 cellForItemAtIndexPath 中的 imageView,当用户触摸单元格时,我会更改图像并运行 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])
希望对某人有所帮助。
【讨论】:
【参考方案7】:在我的情况下,它是由使用相同的逻辑引起的
func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool
至于
func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool
以及选择单元格时,突出的是返回错误 - 这阻止了我取消选择该细胞。
希望这会节省一些人的时间 :)
【讨论】:
【参考方案8】:我遇到了同样的问题,如果您进一步调查,您会发现不仅没有调用 diddiselect,而且单元格也没有感知到触摸本身。为我解决的问题是允许异步执行选择并手动设置 selectItem 。 在 cellForItemAt 内。
DispatchQueue.main.async
cell.isSelected = true
collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .init())
如果您不想看到动作,请在动画上使用 .init() 和 false。如果您不使用 async 块包装它,您将看到 UI 在滚动时跳跃。
【讨论】:
以上是关于UICollectionView - 如果选择了单元格,则不调用 didDeselectItemAtIndexPath的主要内容,如果未能解决你的问题,请参考以下文章
如果使用 PHP 选择了单选按钮(当前),如何在 Mysql 数据库中为出勤值添加 +1?
UICollectionView - 如果选择了单元格,则不调用 didDeselectItemAtIndexPath
如果从 UICollectionView 的其他部分中选择了一个单元格,则取消选择所有其他选择