【问题标题】:How to implement Peek & Pop Feature of specific row of a table manually via code?如何通过代码手动实现表格特定行的 Peek & Pop 功能?
【发布时间】:2018-10-18 17:54:22
【问题描述】:

目标

我正在尝试将 peek and pop 功能添加到我的表格行中


【问题讨论】:

  • 你在previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint)方法中设置断点了吗?它被称为?它是否返回视图控制器?你在什么设备上测试?集合视图控制器是在你当前的 VC 上还是细节 vc 上?
  • 这看起来是个不错的解决方案:stackoverflow.com/a/46648566/341994
  • 您发布的错误似乎与您的问题无关。
  • -1,即使是 Apple 也有适当的示例应用程序来展示 peek'n'pop 的实现:developer.apple.com/documentation/uikit/peek_and_pop/…

标签: ios swift uitableview force-touch


【解决方案1】:

您没有从表格视图中获取单元格。所以步骤如下:

  1. 使用UIViewControllerPreviewingDelegate方法中的位置点获取indexPath
  2. 使用indexPathtableView 获取单元格。
  3. 获取单元格后,将单元格框架转换为表格视图框架。
  4. 将框架作为 sourceRect 提供给previewingContext

代码如下:

viewDidLoad

if self.traitCollection.forceTouchCapability == .available {
    registerForPreviewing(with: self, sourceView: tableView)
}

在扩展中:

extension ProfileViewController: UIViewControllerPreviewingDelegate {

    func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
        if let indexPath = tableView.indexPathForRow(at: location), let cell = tableView.cellForRow(at: indexPath) {
            previewingContext.sourceRect = tableView.convert(cell.frame, to: self.tableView)
            guard let detailViewController = storyboard?.instantiateViewController(withIdentifier: "profileDetail") as? ProfileDetailViewController else {
                return nil
            }
            return detailViewController
        }
        return nil
    }

    func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
        self.navigationController?.pushViewController(viewControllerToCommit, animated: true)
    }
}

【讨论】:

  • 如果您没有使用detailViewController 来返回它,您可以去掉guard 并简单地执行return storyboard?.instantiateViewController(withIdentifier: "profileDetail") as? ProfileDetailViewController,这将等同于您当前的代码,但是更短更简单
  • 这个解决方案的问题是你没有注册单元格本身,因此当它们被按下时你不会在它们周围获得动画边框。
【解决方案2】:

通常,我使用简单的单元格扩展来做到这一点:

class ForceTouchCell: UITableViewCell {
    var previewingContext: UIViewControllerPreviewing?

    func registerPreview(on controller: UIViewController, with delegate: UIViewControllerPreviewingDelegate) {
        self.previewingContext = controller.registerForPreviewing(with: delegate, sourceView: self)
    }

    func unregisterPreview(on controller: UIViewController) {
        guard let previewingContext = previewingContext else {
            return
        }

        controller.unregisterForPreviewing(withContext: previewingContext)
        self.previewingContext = nil
    }
}

然后在控制器上:

class MyController: UIViewController, UITableViewDelegate {
    var tableView: UITableView!

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        guard traitCollection.forceTouchCapability != previousTraitCollection?.forceTouchCapability else {
            return
        }

        let visibleCells = tableView.visibleCells
               .compactMap { $0 as? ForceTouchCell }

        if traitCollection.forceTouchCapability == .available {
           visibleCells.forEach {
               $0.registerPreview(on: self, with: self)
           }
        } else {
           visibleCells.forEach {
               $0.unregisterPreview(on: self)
           }
        }
    }

    func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        if let forceTouchCell = cell as? ForceTouchCell {
            if self.traitCollection.forceTouchCapability == .available {
                forceTouchCell.registerPreview(on: self, with: self)
            }
         }
    }

    func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
        if let forceTouchCell = cell as? ForceTouchCell {
            forceTouchCell.unregisterPreview(on: self)
        }
    }
}

extension MyConroller: UIViewControllerPreviewingDelegate {
    func previewingContext(
    _ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint
) -> UIViewController? {
    guard
        let cell = (previewingContext.sourceView as? ForceTouchCell),
        let indexPath = tableView.indexPath(for: cell)
    else {
        return nil
    }

    // use the indexPath/cell to create preview controller
}

这个解决方案的好处是它可以很容易地在控制器之间共享,例如使用具有默认实现的协议。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-31
    • 1970-01-01
    • 2016-01-06
    • 2019-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-15
    相关资源
    最近更新 更多