问题
I have a UICollectionView that shows 'Peek' when 3D Touch'ed. As default behavior, 'Peek' ignores navigation bars.
However, I do want to show a bar just as in iMessage Peek shown below:
Both Collection View Controller & Peek View Controller are inside Navigation View Controller.
I have following snippet from Apple's Sample code below that I am trying to modify in to above needs:
extension ChatTableViewController: UIViewControllerPreviewingDelegate {
    func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
        guard let indexPath = tableView.indexPathForRow(at: location) else { return nil }
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let viewController = storyboard.instantiateViewController(withIdentifier: ChatDetailViewController.identifier)
        guard let chatDetailViewController = viewController as? ChatDetailViewController else { return nil }
        chatDetailViewController.chatItem = chatItem(at: indexPath)
        let cellRect = tableView.rectForRow(at: indexPath)
        previewingContext.sourceRect = previewingContext.sourceView.convert(cellRect, from: tableView)
        chatDetailViewController.isReplyButtonHidden = true
        return chatDetailViewController
    }
    func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
        if let chatDetailViewController = viewControllerToCommit as? ChatDetailViewController {
            chatDetailViewController.isReplyButtonHidden = false
        }
        show(viewControllerToCommit, sender: self)
    }
UPDATE
Thanks to Leo Natan I was able to accomplish above:
extension ChatTableViewController: UIViewControllerPreviewingDelegate {
    func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
        guard let indexPath = tableView.indexPathForRow(at: location) else { return nil }
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let viewController = storyboard.instantiateViewController(withIdentifier: ChatDetailViewController.identifier)
        guard let chatDetailViewController = viewController as? ChatDetailViewController else { return nil }
        chatDetailViewController.chatItem = chatItem(at: indexPath)
        let cellRect = tableView.rectForRow(at: indexPath)
        previewingContext.sourceRect = previewingContext.sourceView.convert(cellRect, from: tableView)
        chatDetailViewController.isReplyButtonHidden = true
        let navigationController = UINavigationController(rootViewController: viewController
        return navigationController
    }
    func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
        if let chatDetailViewController = viewControllerToCommit as? ChatDetailViewController {
            chatDetailViewController.isReplyButtonHidden = false
        }
        show(viewControllerToCommit, sender: self)
    }
However, this creates a NEW Navigation Controller. If I want to end up with the same same Navigation Controller, I can do this:
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
    if let chatDetailViewController = viewControllerToCommit as? ChatDetailViewController {
        chatDetailViewController.isReplyButtonHidden = false
    }
    show((viewControllerToCommit as UIController).viewControllers[0], sender: self)
}
show((viewControllerToCommit as UIController).viewControllers[0], sender: self) extracts the viewController out of it's Navigation Controller. Does this have any downsides?
回答1:
In previewingContext(_:, viewControllerForLocation:), wrap your view controller in a UINavigationController and return that.
来源:https://stackoverflow.com/questions/41768803/3d-touch-peek-with-top-bar