我该如何实施"向右拖动以解雇"导航堆栈中的视图控制器?

时间:2016-02-14 06:18:13

标签: ios swift

默认情况下,如果从屏幕的左边缘向右拖动,它将拖走ViewController并将其从堆栈中取出。

我想将此功能扩展到整个屏幕。当用户在任何地方拖动时,我也希望发生同样的事情。

我知道我可以实现向右滑动手势,只需拨打<% if %> <% else %> <% end %>

即可

然而,没有&#34;拖动&#34;运动。我希望用户能够右键拖动视图控制器,就好像它是一个对象,揭示了它下面的内容。并且,如果它被拖过50%,则将其解雇。 (查看Instagram以了解我的意思。)

7 个答案:

答案 0 :(得分:26)

enter image description here

在Github制作了一个演示项目https://github.com/rishi420/SwipeRightToPopController

我已使用UIViewControllerAnimatedTransitioning协议

来自doc:

  

//这用于百分比驱动的交互式转换,以及容器控制器......

在控制器的视图中添加了UIPanGestureRecognizer。这是手势的动作:

func handlePanGesture(panGesture: UIPanGestureRecognizer) {

    let percent = max(panGesture.translationInView(view).x, 0) / view.frame.width

    switch panGesture.state {

    case .Began:
        navigationController?.delegate = self
        navigationController?.popViewControllerAnimated(true)

    case .Changed:
        percentDrivenInteractiveTransition.updateInteractiveTransition(percent)

    case .Ended:
        let velocity = panGesture.velocityInView(view).x

        // Continue if drag more than 50% of screen width or velocity is higher than 1000
        if percent > 0.5 || velocity > 1000 {
            percentDrivenInteractiveTransition.finishInteractiveTransition()
        } else {
            percentDrivenInteractiveTransition.cancelInteractiveTransition()
        }

    case .Cancelled, .Failed:
        percentDrivenInteractiveTransition.cancelInteractiveTransition()

    default:
        break
    }
}

步骤:

  1. 计算视图上拖动的百分比
  2. .Begin:指定要执行的segue并指定UINavigationController委托。 InteractiveTransitioning
  3. 需要委托
  4. .Changed: UpdateInteractiveTransition with percentage
  5. .Ended:如果拖动50%或更高或更高速度,则继续保持转换
  6. .Cancelled, .Failed:取消转换

  7. 参考文献:

    1. UIPercentDrivenInteractiveTransition
    2. https://github.com/visnup/swipe-left
    3. https://github.com/robertmryan/ScreenEdgeGestureNavigationController
    4. https://github.com/groomsy/custom-navigation-animation-transition-demo

答案 1 :(得分:3)

@Warif Akhand Rishi接受的答案的Swift 4版本

即使此答案确实有效,我还是发现了2个怪癖。

  1. 如果您向左滑动,它也会消失,就像您向右滑动一样。
  2. 这也是非常微妙的,因为即使在任一方向上轻轻滑动,也将关闭vc。

除此之外,它肯定可以正常工作,您可以左右滑动以将其关闭。

class ViewController: UIGestureRecognizerDelegate, UINavigationControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationController?.interactivePopGestureRecognizer?.delegate = self
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))
        view.addGestureRecognizer(panGesture)
    }

    @objc func handlePanGesture(_ gesture: UIPanGestureRecognizer){

        let interactiveTransition = UIPercentDrivenInteractiveTransition()

        let percent = max(gesture.translation(in: view).x, 0) / view.frame.width

        switch gesture.state {

        case .began:
            navigationController?.delegate = self
            navigationController?.popViewController(animated: true)

        case .changed:
            interactiveTransition.update(percent)

        case .ended:
            let velocity = gesture.velocity(in: view).x

            // Continue if drag more than 50% of screen width or velocity is higher than 1000
            if percent > 0.5 || velocity > 1000 {
                interactiveTransition.finish()
            } else {
                interactiveTransition.cancel()
            }

        case .cancelled, .failed:
            interactiveTransition.cancel()

        default:break
        }
    }
}

答案 2 :(得分:2)

您需要调查UINavigationController的{​​{3}}属性。

这是一个类似的问题,带有示例代码来解决这个问题。

interactivePopGestureRecognizer

答案 3 :(得分:2)

创建一个平移手势识别器,并在其中移动交互式弹出手势识别器的目标。

将您的识别器添加到推送的视图控制器的viewDidLoad中,瞧!

let popGestureRecognizer = self.navigationController!.interactivePopGestureRecognizer!
if let targets = popGestureRecognizer.value(forKey: "targets") as? NSMutableArray {
  let gestureRecognizer = UIPanGestureRecognizer()
  gestureRecognizer.setValue(targets, forKey: "targets")
  self.view.addGestureRecognizer(gestureRecognizer)
}

答案 4 :(得分:0)

向右轻扫以关闭视图控制器

Swift 5版本- (从右向左滑动时也删除了手势识别)

重要- 在VC2的“属性检查器”中,将“演示文稿”值从“全屏”设置为“全屏”。这样一来,在通过手势关闭VC2时,可以看到VC1。如果没有手势,VC2后面会出现黑屏,而不是VC1。

class ViewController: UIGestureRecognizerDelegate, UINavigationControllerDelegate {

    var initialTouchPoint: CGPoint = CGPoint(x: 0, y: 0)

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationController?.interactivePopGestureRecognizer?.delegate = self
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))
        view.addGestureRecognizer(panGesture)
    }

    @objc func handlePanGesture(_ sender: UIPanGestureRecognizer) {
        let touchPoint = sender.location(in: self.view?.window)
        let percent = max(sender.translation(in: view).x, 0) / view.frame.width
        let velocity = sender.velocity(in: view).x

        if sender.state == UIGestureRecognizer.State.began {
            initialTouchPoint = touchPoint
        } else if sender.state == UIGestureRecognizer.State.changed {
            if touchPoint.x - initialTouchPoint.x > 0 {
                self.view.frame = CGRect(x: touchPoint.x - initialTouchPoint.x, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height)
            }
        } else if sender.state == UIGestureRecognizer.State.ended || sender.state == UIGestureRecognizer.State.cancelled {

            if percent > 0.5 || velocity > 1000 {
                navigationController?.popViewController(animated: true)
            } else {
                UIView.animate(withDuration: 0.3, animations: {
                    self.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height)
                })
            }
        }
    }
}

希望这会有所帮助。 如有必要,随时提出更改建议。

答案 5 :(得分:0)

我认为这比建议的解决方案容易,并且也适用于该导航内的所有viewController以及嵌套的滚动视图。

https://stackoverflow.com/a/58779146/8517882

只需安装吊舱,然后使用EZNavigationController而不是UINavigationController来使该导航控制器内的所有视图控制器具有此行为。

答案 6 :(得分:-3)

您可以使用滑动右手势来实现此目的:

override func viewDidLoad() {
    super.viewDidLoad()

    var swipeRight = UISwipeGestureRecognizer(target: self, action: "popViewController:")
    swipeRight.direction = UISwipeGestureRecognizerDirection.Right
    self.view.addGestureRecognizer(swipeRight)
}


func popViewController(gesture: UIGestureRecognizer) {

    if let swipeGesture = gesture as? UISwipeGestureRecognizer {
        switch swipeGesture.direction {
            case UISwipeGestureRecognizerDirection.Right:
               self.navigationController.popViewControllerAnimated(true)
            default:
                break
        }
    }
}