Have video: After Peek and Pop (3D Touch) background keeps scrolling

330 views Asked by At

Video of the bug: Video

I have a regular table view with UITableViewCells. It looks like messages. I have another view controller OperationDetailsViewController.

In table view delegate I have this:

// need that dict for 3D touch
var dict_previwingControllers_cellIsKey = [UITableViewCell: UIViewControllerPreviewing]()

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {

    // setup peek and pop (register proper view)
    if traitCollection.forceTouchCapability == .available, let cellForChat = cell as? OperationsSingleCell {
        let previewingController = registerForPreviewing(with: self, sourceView: cellForChat.viewTextBG)
        dict_previwingControllers_cellIsKey[cell] = previewingController // remember because we need to unregister
    }
}

func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    // setup peek and pop (unregister)
    if traitCollection.forceTouchCapability == .available {
        if let previwingController = dict_previwingControllers_cellIsKey[cell] {
            unregisterForPreviewing(withContext: previwingController)
        }
    }
}

To show preview when user taps on message background I have this:

/// Create a previewing view controller to be shown at "Peek".
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
    // Obtain cell by previewing context
    guard let cell = (dict_previwingControllers_cellIsKey as NSDictionary).allKeys(for: previewingContext).first as? OperationsSingleCell else {return nil}
//        guard let indexPath = tableViewMain.indexPathForRow(at: location),
//            let cell = tableViewMain.cellForRow(at: indexPath) as? OperationsSingleCell else { return nil }


    guard let operationDetailsVC = storyboard?.instantiateViewController(withIdentifier: "OperationDetailsVC") as? OperationDetailsVC else {return nil}
    // custom properties
    operationDetailsVC.dbOrder = cell.dbOrder
    operationDetailsVC.navigationControllerOfParentVC = navigationController
    // need to load view so we will know content size
    operationDetailsVC.view.reloadInputViews()

    let contentHeight = operationDetailsVC.scrollViewMain.contentSize.height

    /*
     Set the height of the preview by setting the preferred content size of the detail view controller.
     Width should be zero, because it's not used in portrait.
     */
    operationDetailsVC.preferredContentSize = CGSize(width: 0.0, height: contentHeight)

    // Set the source rect to the cell frame, so surrounding elements are blurred.
    previewingContext.sourceRect = cell.viewTextBG.bounds

    return operationDetailsVC
}

/// Present the view controller for the "Pop" action.
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
    // Reuse the "Peek" view controller for presentation.
    show(viewControllerToCommit, sender: self)
}

But when user uses 3D Touch background keeps scrolling like on the video

It strange because in iMessage application it doesn't happen

1

There are 1 answers

1
Willjay On

I've tried with default tableView and I don't have the situation. That it to say, when I 3d touch my tableView cell, it pops up the detailView, and the background view (tableView) is not scrollable.

Also, you don't have to register for previewing every cell, you can just register the whole tableview cell at once.

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

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

}

extension ViewController: UITableViewDataSource, UITableViewDelegate {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 20
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = "Hello World"
        return cell
    }
}

PreviewDelegate

extension ViewController: UIViewControllerPreviewingDelegate {
    func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
        guard let indexPath = tableView.indexPathForRow(at: location) else { return nil }
        guard let cell = tableView.cellForRow(at: indexPath) else { return nil }

        guard let operationDetailsVC = storyboard?.instantiateViewController(withIdentifier: "OperationDetailsVC") as? OperationDetailsVC else { return nil }

        operationDetailsVC.preferredContentSize = CGSize(width: 0, height: 300)
        previewingContext.sourceRect = cell.frame

        // You can decide to return a viewController or nil for certain cell
        return operationDetailsVC

    }

    func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
        show(viewControllerToCommit, sender: self)
    }
}