检测何时取消 3D Touch Peek 和 Pop View

Posted

技术标签:

【中文标题】检测何时取消 3D Touch Peek 和 Pop View【英文标题】:Detect when 3D Touch Peek and Pop View is Canceled 【发布时间】:2018-02-27 14:35:38 【问题描述】:

我有一个启用了 3D Touch Peek and Pop 的 UITableView。我希望能够检测到用户何时偷看视图以及何时用户停止偷看视图而不弹出。我知道previewingGestureRecognizerForFailureRelationship 存在。我试过这样使用它:

func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? 

        // Here's where I add the gesture
        let gesture = previewingContext.previewingGestureRecognizerForFailureRelationship
        gesture.addObserver(self, forKeyPath: "state", options: .new, context: nil)

        let sb = UIStoryboard(name: "Main", bundle: nil)
        let detailVC = sb.instantiateViewController(withIdentifier: "SongPreviewViewController") as? SongPreviewViewController

        return detailVC
    

然后我添加

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) 

        // can recognize peeking and canceling commit
        if let object = object 
            if keyPath == "state" 
                let newValue = (change![NSKeyValueChangeKey.newKey]! as AnyObject).integerValue
                let state = UIGestureRecognizerState(rawValue: newValue!)!
                switch state 
                case .possible:
                    print("switch - possible")
                case .began:
                    print("switch - began")
                case .changed:
                    print("switch - changed")
                case .ended:
                    print("switch - ended")
                case .cancelled:
                    print("switch - cancelled")
                case .failed:
                    print("switch - failed")
                
            
        
    

但每次查看视图开始时,都会调用.ended。有谁知道如何正确地做到这一点? Here's the reference I used for this code.感谢您的帮助!

【问题讨论】:

【参考方案1】:

UITapGestureRecognizer 仅在手势状态为 UIGestureRecognizerStateEnded 时触发,如下链接所述:

About messages from UITapGestureRecognizer

所有手势识别器都在可能状态 (possible) 开始一个多点触控序列。如果您希望获得最多两种状态:(.Possible) 和 (.end) 你可以试试这段代码(Xcode 9.2,swift 3.2,target 11.2)。

    更改您的 addObserver 代码(添加更多选项):

    gesture.addObserver(self, forKeyPath: "state", options: [.prior, .old, .new], context: nil)
    

    在您的 observeValue 方法中获取旧值和新值,如下所示。它将调用 (.possible)(.end) 状态:

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)      
    // can recognize peeking and canceling commit
    if let object = object 
        if keyPath == "state" 
            var newValue:Int?
            guard let change = change else  return 
            let old = change[.oldKey] == nil || change[.oldKey] as? NSNull != nil ? "nil" : "\(change[.oldKey]!)"
            let new = change[.newKey] == nil || change[.newKey] as? NSNull != nil ? "nil" : "\(change[.newKey]!)"
            if change[.notificationIsPriorKey] as? Bool == true 
                newValue = (old as AnyObject).integerValue
            
            else 
                 newValue = (new as AnyObject).integerValue
            
            let state = UIGestureRecognizerState(rawValue: newValue!)!
            switch state 
            case .possible:
                print("switch - possible")
            case .began:
                print("switch - began")
            case .changed:
                print("switch - changed")
            case .ended:
                print("switch - ended")
            case .cancelled:
                print("switch - cancelled")
            case .failed:
                print("switch - failed")
            
        
    
    

【讨论】:

【参考方案2】:

还有另一个函数previewingContext(_:commit:) 用于告诉您它将提交。您可以使用它来设置一个属性,如果没有设置,您可以判断 3D Touch 动作没有“弹出”。 Documentation.

【讨论】:

以上是关于检测何时取消 3D Touch Peek 和 Pop View的主要内容,如果未能解决你的问题,请参考以下文章

如何实现 3D-Touch Peek-and-select?

带导航控制器的 3D Touch Peek/Pop

通过 Longpress 使用 3D touch peek and pop

使用 3D Touch 的精简预览视图

iOS开发之3D Touch

3D Touch:在展开可选值时意外发现 nil