Tableview 上下文菜单:从行到预览视图控制器的自定义动画

Posted

技术标签:

【中文标题】Tableview 上下文菜单:从行到预览视图控制器的自定义动画【英文标题】:Tableview context menu: custom animation from row to a preview view controller 【发布时间】:2019-12-22 13:23:28 【问题描述】:

我已经为 tableview 实现了特定于行的上下文菜单,其中包括一个简单的预览视图控制器,如下所示。

我想实现一个过渡或动画,以便 tableview 中的图标(UIImageView)在预览视图控制器中作为图标动画定位。

但是,看着documentation(特别是UITargetedPreviewUIPreviewTarget),我无法弄清楚如何在具有多行的tableview 的上下文中创建这样的动画。


预览视图控制器是根据行使用数据模型中的图标生成的,如下所示:

class DrugPreviewViewController: UIViewController 
    private let imageView = UIImageView()

    override func loadView() 
        view = imageView
    

    init(item: CustomItem) 
        super.init(nibName: nil, bundle: nil)

        // Set up image view
        imageView.clipsToBounds = true
        imageView.contentMode = .scaleAspectFill
        imageView.backgroundColor = .clear
        imageView.image = UIImage(named: item.icon ?? "defaultIcon")?.withRenderingMode(.alwaysTemplate).tinted(with: Color.colors[item.iconBackgroundColor ?? 0])
        // Preview to have the same aspect ratio as the image
        preferredContentSize = UIImage(named: item.icon ?? "defaultIcon")!.size
    

    required init?(coder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    

缩短的上下文菜单代码如下所示:

@available(ios 13.0, *)
override func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? 

    // Selected Drug and notes
    let selectedItem: CustomItem = dataArray[indexPath.row]

    var notes = selectedItem.notes ?? ""
    var titleString = selectedItem.name

    // Code for menu items and actions
    // Defines actions array
    // Omitted for brevity

    let actionProvider: UIContextMenuActionProvider =  _ in
        return UIMenu(title: titleString, children: actions)
    

    return UIContextMenuConfiguration(identifier: indexPath as NSCopying, previewProvider: 
        return CustomPreviewViewController(item: selectedItem)
    , actionProvider: actionProvider)

【问题讨论】:

【参考方案1】:

感谢article by Kyle Bashour,我找到了一个本地 Cocoa 解决方案,而无需自己进行详细的转换。

似乎所有标准的单视图上下文菜单 UIContextMenuInteractionDelegate 方法都具有等效的 UITableViewDelegate 方法,用于在表格视图中实现上下文菜单。

我设法实现了如下所示的结果。它不会将图标动画到中间的预览中,但它足够接近我想要的并且看起来比我以前的要好得多。

为了实现这一点,我需要在上面返回上下文菜单的代码中设置previewProvider nil:

return UIContextMenuConfiguration(identifier: indexPath as NSCopying, previewProvider: nil, actionProvider: actionProvider)

然后我必须实现这两个委托方法——它们都调用相同的代码块来返回一个UITargetedPreview

@available(iOS 13.0, *)
override func tableView(_ tableView: UITableView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? 
    return makeTargetedPreview(for: configuration)



@available(iOS 13.0, *)
override func tableView(_ tableView: UITableView, previewForDismissingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? 
    return makeTargetedPreview(for: configuration)


@available(iOS 13.0, *)
private func makeTargetedPreview(for configuration: UIContextMenuConfiguration) -> UITargetedPreview? 
    guard let indexPath = configuration.identifier as? IndexPath else  return nil 
    // Get the cell for the index of the model
    guard let cell = tableView.cellForRow(at: indexPath) as? DrugTableViewCell else  return nil 
    // Set parameters to a circular mask and clear background
    let parameters = UIPreviewParameters()
    parameters.backgroundColor = .clear
    parameters.visiblePath = UIBezierPath(ovalIn: cell.iconView.bounds)

    // Return a targeted preview using our cell previewView and parameters
    return UITargetedPreview(view: cell.iconView, parameters: parameters)

cell.iconView 是我自定义的UITableViewCell 中的UIImageView


请注意,在显示菜单时表格数据发生变化的情况下,为了安全起见,Kyle 建议使用实际数据模型(通过索引路径访问)来获取预览所需的数据(而不是单元格)。有关详细信息,请参阅他的文章。

【讨论】:

谢谢。拯救我的一天。 @PowHu 很高兴它有帮助! 为什么它被接受为正确答案? configuration.identifier as? IndexPath 要求您使用您跳过的contextMenuConfigurationForRowAt 并以某种方式传递与NSCopying 不相符的IndexPath,这是必需的! @VyachaslavGerchicov 代码indexPath as NSCopying 通过强制转换实现了这一点。 请注意,indexPath 会超出其有效范围。【参考方案2】:

我认为实现UIViewControllerAnimatedTransitioning 协议可以让您朝着正确的方向前进。首先有点复杂。这是一个如何执行此操作的示例

https://github.com/dasdom/DDHCustomTransition/blob/master/DDHCustomTransition/Transition/CustomTransition.swift

【讨论】:

非常感谢您的建议 - 我会检查一下。我不知道那个协议。

以上是关于Tableview 上下文菜单:从行到预览视图控制器的自定义动画的主要内容,如果未能解决你的问题,请参考以下文章

在 iPad 上的上下文菜单中点击预览不会为全屏视图控制器的演示设置动画

SwiftUI 中的上下文菜单预览没有圆角

从行到列的 SQL 结果

C-shell:从行到列打印结果

幻灯片视图控制器

iOS13上下文菜单点击时如何显示或导航到当前的查看视图