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

UIKit Swift:上下文菜单关闭后阴影延迟显示问题求助

问题:关闭上下文菜单后,CollectionView单元格阴影延迟显示

我有一个带阴影的CollectionView单元格,给它添加了上下文菜单。关闭菜单后,单元格及其内部元素的阴影会有大约0.5秒的延迟才显示出来,不清楚问题出在哪里。相关代码如下:

func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
    
    if collectionView == foodOnTheShelf {
        
        let config = UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in

            let edit = UIAction(title: "Изменить", image: UIImage(systemName: "pencil"), identifier: nil, discoverabilityTitle: nil, state: .off) { _ in
                self.alert.showAlert(viewController: self,
                                     image:  UIImage(named: test[indexPath.row].name)!,
                                     food: test[indexPath.row],
                                     picker: self.picker,
                                     consumePicker: self.consumePicker,
                                     unit: self.unit,
                                     currentWeigt: test[indexPath.row].weight,
                                     currentProductDate: test[indexPath.row].productionDate,
                                     currentExperationDate: test[indexPath.row].expirationDate,
                                     searchController: nil)
            }
            
            let delete = UIAction(title: "Удалить", image: UIImage(systemName: "trash"), attributes: .destructive) { _ in
                test.remove(at: indexPath.row)
                self.viewDidAppear(true)
            }
            return UIMenu(title: "", image: nil, identifier: nil, options: UIMenu.Options.displayInline , children: [edit, delete])
        }
        return config
    }
 return nil
}

解决方案

这个延迟问题大概率和上下文菜单关闭后的动画冲突,或是单元格阴影的渲染未及时触发更新,可从以下几个方向修复:

  • 禁止手动调用生命周期方法
    你在删除操作里直接调用viewDidAppear(true),这是错误的用法——生命周期方法不应手动触发。正确的做法是用CollectionView的专用更新方法,避免干扰视图渲染流程:

    let delete = UIAction(title: "Удалить", image: UIImage(systemName: "trash"), attributes: .destructive) { _ in
        test.remove(at: indexPath.row)
        self.foodOnTheShelf.deleteItems(at: [indexPath])
    }
    
  • 监听菜单关闭事件,强制刷新单元格
    通过UIContextMenuInteractionDelegate的方法监听菜单关闭,然后触发对应单元格的图层重绘,确保阴影及时显示:

    func contextMenuInteractionDidEnd(_ interaction: UIContextMenuInteraction) {
        guard let indexPath = foodOnTheShelf.indexPathsForSelectedItems?.first else { return }
        if let cell = foodOnTheShelf.cellForItem(at: indexPath) {
            cell.layer.setNeedsDisplay()
            cell.layoutIfNeeded()
        }
    }
    
  • 检查单元格阴影的设置逻辑
    确保阴影设置在单元格的主图层而非contentView上,同时可开启光栅化优化渲染性能,避免层级导致的延迟:

    // 在单元格初始化方法中配置阴影
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupShadow()
    }
    
    private func setupShadow() {
        layer.shadowColor = UIColor.black.cgColor
        layer.shadowOpacity = 0.2
        layer.shadowOffset = CGSize(width: 0, height: 2)
        layer.shadowRadius = 4
        layer.masksToBounds = false
        // 可选:开启光栅化提升重复渲染性能
        layer.shouldRasterize = true
        layer.rasterizationScale = UIScreen.main.scale
    }
    
  • 菜单关闭后立即触发布局刷新
    如果以上方法无效,可以在菜单创建时,通过异步队列触发CollectionView的布局失效,强制更新视图:

    let config = UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { [weak self] _ in
        // ... 菜单操作定义
        let menu = UIMenu(title: "", image: nil, identifier: nil, options: .displayInline , children: [edit, delete])
        DispatchQueue.main.async {
            self?.foodOnTheShelf.collectionViewLayout.invalidateLayout()
        }
        return menu
    }
    

内容的提问来源于stack exchange,提问作者himynameisartem

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 23:19:01