【问题标题】:CLIENT APP ERROR - Neither the view or container of the UITargetedPreview is currently in a window客户端应用程序错误 - UITargetedPreview 的视图或容器当前都不在窗口中
【发布时间】:2020-05-15 22:37:03
【问题描述】:

我正在尝试修复 Xcode 控制台中的 UIKit 警告请求帮助:

客户端应用程序错误 - UITargetedPreview 的视图或容器当前都不在窗口中。这违反了 UIDragInteraction API 合同,并可能导致严重的视觉故障。

我有一个UITableView 的拖动源,它实现了UITableViewDragDelegate。表视图位于拆分视图主视图内,目标位于拆分视图控制器内。拖放交互完美运行。问题是来自 Xcode 的相当可怕的错误!

UIDragItem 由以下人员生成:

extension Store: NSItemProviderWriting {  

    var dragItem: UIDragItem {  
        let dragItem = UIDragItem(itemProvider: NSItemProvider(object: self))  
        dragItem.localObject = self  
        dragItem.previewProvider = {  
            let image = UIImageView(image: self.imageFront)  
            image.frame = CGRect(x: 0, y: 0, width: 40, height: 40) // magic number for store preview size  
            return UIDragPreview(view: image)  
        }  
        return dragItem  
    }  
}  

我已尝试中断所有 UIDragDelegate 方法,但在生成预览时出现警告,这似乎是在此过程的后期。

我会发布我的拖动方法,看看我是否遗漏了什么。

提前致谢。

// MARK: - Table view drag delegate  

extension StoresTableViewController: UITableViewDragDelegate {  
    func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {  
        return [stores[indexPath.row].dragItem]  
    }  

    func tableView(_ tableView: UITableView, dragSessionWillBegin session: UIDragSession) {  
        guard let draggedStore = session.items.first?.localObject as? Store else { return }  
        if draggedStore.maxSimilarStores > session.items.count {  
            tableView.performBatchUpdates({  
                let index = stores.firstIndex(of: draggedStore)!  
                stores.remove(at: index)  
                stores.insert(draggedStore.copy() as! Store, at: index)  
                tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .fade)  
            }, completion: nil)  
        }  
    }  

    func tableView(_ tableView: UITableView, itemsForAddingTo session: UIDragSession, at indexPath: IndexPath, point: CGPoint) -> [UIDragItem] {  
        guard let draggedStore = session.items.first?.localObject as? Store else { return [] }  
        let tableStore = stores[indexPath.row]  
        if draggedStore.name == tableStore.name && draggedStore.maxSimilarStores > session.items.count {  
            return [tableStore.dragItem]  
        } else {  
            return []  
        }  
    }  

    func tableView(_ tableView: UITableView, dragPreviewParametersForRowAt indexPath: IndexPath) -> UIDragPreviewParameters? {  
        guard let cell = tableView.cellForRow(at: indexPath) as? StoreTableViewCell else { return nil }  
        let parameters = UIDragPreviewParameters()  
        parameters.visiblePath = UIBezierPath(rect: cell.storeImageView.frame)  
        return parameters  
    }  
} 

我已经创建了一个调试项目来重现:

https://github.com/atapp/iTOLD_DEBUG

谢谢

【问题讨论】:

    标签: ios swift uikit


    【解决方案1】:

    我对此的解决方案是放弃UITableViewDragDelegate 并从自定义UITableViewCell 实现拖动交互。我不确定这是否是正确的方法,但它已经清除了错误。

    对于拖放的简单演示,Imanou Petit Drag UIView between UIViews 的这个答案很有用。显然苹果文档Making a View into a Drag Source

    对我来说,线索在于错误本身,抱怨UITargetedPreview 缺少视图或容器。据我所知,UITargetedPreview 不是UITableViewDelegate 系统的一部分,我假设是因为UITableViewDelegate 系统纯粹是为在UITableView 本身内绘制和放置而设计的。

    我的用途不同,我试图从UITableView 拖动到任何地方。

    TLDR;

    新的UITableView 删除了所有UITableViewDragDelegate 方法并添加了所需的自定义单元初始化器:

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "StoreCell", for: indexPath) as! StoreTableViewCell
            let dragInteraction = UIDragInteraction(delegate: cell)
            cell.addInteraction(dragInteraction)
            cell.store = stores[indexPath.row]
            {...}
            return cell
        }
    

    自定义的UITableViewCell 是:

    class StoreTableViewCell: UITableViewCell {
    
        var store: Store?
    
        override func awakeFromNib() {
            super.awakeFromNib()
            // Initialization code
        }
    
        {...}
    }
    
    extension StoreTableViewCell: UIDragInteractionDelegate {
        func dragInteraction(_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] {
            if let dragItem = store?.dragItem {
                return [dragItem]
            }
            return []
        }
    
        func dragInteraction(_ interaction: UIDragInteraction, previewForLifting item: UIDragItem, session: UIDragSession) -> UITargetedDragPreview? {
            if let store = store, let frontImage = store.imageFront {
                let imageView = UIImageView(image: frontImage)
                imageView.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
                let target = UIPreviewTarget(container: storeImageView, center: session.location(in: storeImageView))
                let parameters = UIPreviewParameters()
                parameters.backgroundColor = .clear
                let preview = UITargetedDragPreview(view: imageView, parameters: parameters, target: target)
                return preview
            }
            return nil
        }
    }
    

    注意UIPreviewTarget 是自定义UITableViewCell 中的图像(尽管我希望这可以是任何视图),我从UIDragSession 中心设置预览中心。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-28
      • 1970-01-01
      • 2012-12-10
      相关资源
      最近更新 更多