You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在UICollectionView中通过单击显示上下文菜单?(已实现长按触发功能)

实现UICollectionView单击单元格显示上下文菜单

好问题!你已经搞定了长按触发菜单的逻辑,现在要让单击也复用这套菜单,其实有两种可行的方案,分版本兼容来给你说明:


方案一:兼容iOS 13+ 的通用方案

这个方案可以覆盖iOS 13及以上的所有版本,核心思路是复用你已经写好的configureContextMenu(index:)方法,通过手动创建UIContextMenuInteraction来触发菜单展示:

步骤1:让ViewController遵守UIContextMenuInteractionDelegate

先给你的BackupViewController添加协议扩展:

extension BackupViewController: UIContextMenuInteractionDelegate {
    func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
        // 从交互对象中取出存储的单元格索引
        guard let selectedIndex = interaction.value(forKey: "selectedIndex") as? Int else {
            return nil
        }
        // 直接复用已有的菜单配置逻辑
        return configureContextMenu(index: selectedIndex)
    }
}

步骤2:修改didSelectItemAt方法

在单击回调里,给目标单元格添加交互并触发菜单:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    guard let cell = collectionView.cellForItem(at: indexPath) else {
        return
    }
    
    // 先移除单元格上已有的上下文菜单交互,避免重复添加
    cell.interactions
        .filter { $0 is UIContextMenuInteraction }
        .forEach { cell.removeInteraction($0) }
    
    // 创建新的上下文菜单交互
    let interaction = UIContextMenuInteraction(delegate: self)
    // 把当前单元格的索引存储到交互对象中,方便后续获取
    interaction.setValue(indexPath.row, forKey: "selectedIndex")
    cell.addInteraction(interaction)
    
    // 在单元格中心位置弹出菜单
    interaction.presentMenu(
        at: CGPoint(x: cell.bounds.midX, y: cell.bounds.midY),
        in: cell,
        animated: true
    )
}

方案二:iOS 16+ 简化方案

如果你的APP只需要支持iOS 16及以上,代码可以更简洁,直接调用UIView的原生方法:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    guard let cell = collectionView.cellForItem(at: indexPath) else {
        return
    }
    
    // 获取已配置好的上下文菜单配置
    let menuConfig = configureContextMenu(index: indexPath.row)
    // 取出配置里的UIMenu实例
    guard let menu = menuConfig.menuProvider?() else {
        return
    }
    
    // 在整个单元格范围内弹出菜单
    cell.showMenu(menu, sourceRect: cell.bounds)
}

这个方案省去了处理交互代理的步骤,代码更清爽,但仅限iOS 16+使用。


两种方案都能实现你想要的效果:单击单元格时弹出和长按完全一致的上下文菜单,而且完美复用了你已经写好的菜单配置逻辑,不需要重复编写代码~

内容的提问来源于stack exchange,提问作者Cheok Yan Cheng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 14:02:33