拖动UIView

时间:2017-11-30 19:36:13

标签: ios swift gesture pan

我需要一些帮助,拖动UIView以显示主视图下方的菜单视图。

我有两个UIView个。 menuView - 包括菜单按钮和标签  和mainView - 位于menuView之上。

我想从左边缘拖动主视图以显示菜单项并将主视图捕捉到特定位置。我可以将拖动向右移动,但是当向左拖动时我无法将其设置回原始位置。

这是我一直在玩的代码,但没有成功。 当我向右拖动时,我也想让mainView变小。 任何帮助将不胜感激。

注意:PanGesture附加到mainView

@IBAction func dragMenu(_ sender: UIPanGestureRecognizer) {
    let mview = sender.view!
    let originalCenter = CGPoint(x: self.mainView.bounds.width/2, y: self.mainView.bounds.height/2)
    switch sender.state {

    case .changed:
        if let mview = sender.view {
            mview.center.x = mview.center.x + sender.translation(in: view).x
            sender.setTranslation(CGPoint.zero, in: view)
        }

    case .ended:


            let DraggedHalfWayRight = mview.center.x > view.center.x
            if DraggedHalfWayRight {
                //dragginToRight

                showMenu = !showMenu
                self.mainViewRight.constant = 200
                                    self.mainTop.constant = 50
                                    self.mainBottom.constant = 50
                                    self.mainLeft.constant = 200

            } else //dragging left and set it back to original position.
            {
                mview.center = originalCenter
                 showMenu = !showMenu
        }



    default:
        break
    }
}

1 个答案:

答案 0 :(得分:0)

我建议一些事情:

  1. 当您完成拖动菜单后,请确保将其alpha设置为零(如果您是在纵向并转到横向,则不要突然看到菜单坐在那里。

  2. 我个人只是调整拖动视图的transform,并避免将手势的平移重置为零。这是个人偏好的问题。

  3. 我将视图控制器作为手势的委托并实现gestureRecognizerShouldBegin(因为如果菜单被隐藏,您不想识别滑动以尝试再次隐藏它;如果它不是隐藏的,你不想识别滑动以显示它。)

  4. 在确定是否完成手势时,我还会考虑手势的速度(例如,稍微轻弹就会消除/显示动画视图)。

  5. 因此:

    class ViewController: UIViewController {
    
        @IBOutlet weak var menuView: UIView!
    
        var isMenuVisible = true
    
        @IBAction func dragMenu(_ gesture: UIPanGestureRecognizer) {
            let translationX = gesture.translation(in: gesture.view!).x
    
            switch gesture.state {
            case .began:
                // if the menu is not visible, make sure it's off screen and then make it visible
    
                if !isMenuVisible {
                    menuView.transform = CGAffineTransform(translationX: gesture.view!.bounds.width, y: 0)
                    menuView.alpha = 1
                }
                fallthrough
    
            case .changed:
                if isMenuVisible {
                    menuView.transform = CGAffineTransform(translationX: translationX, y: 0)
                } else {
                    menuView.transform = CGAffineTransform(translationX: gesture.view!.bounds.width + translationX, y: 0)
                }
    
            case .ended:
                let shouldComplete: Bool
                if isMenuVisible {
                    shouldComplete = translationX > gesture.view!.bounds.width / 2 || gesture.velocity(in: gesture.view!).x > 0
                } else {
                    shouldComplete = -translationX > gesture.view!.bounds.width / 2 || gesture.velocity(in: gesture.view!).x < 0
                }
    
                UIView.animate(withDuration: 0.25, animations: {
                    if self.isMenuVisible && shouldComplete || !self.isMenuVisible && !shouldComplete {
                        self.menuView.transform = CGAffineTransform(translationX: gesture.view!.bounds.width, y: 0)
                    } else {
                        self.menuView.transform = .identity
                    }
    
                    if shouldComplete{
                        self.isMenuVisible = !self.isMenuVisible
                    }
                }, completion: { _ in
                    self.menuView.alpha = self.isMenuVisible ? 1 : 0
                })
    
            default:
                break
            }
        }
    
    }
    
    extension ViewController: UIGestureRecognizerDelegate {
    
        func gestureRecognizerShouldBegin(_ gesture: UIGestureRecognizer) -> Bool {
            guard let gesture = gesture as? UIPanGestureRecognizer else { return true }
    
            let translationX = gesture.translation(in: gesture.view!).x
    
            return isMenuVisible && translationX > 0 || !isMenuVisible && translationX < 0
        }
    
    }
    

    就个人而言,我更喜欢使用单独的屏幕边缘手势识别器将它们拉回到屏幕上(你真的不希望它在任何地方识别手势,而只是在右边缘)。这种方法的另一个优点是通过在不同的函数中保持“显示”和“隐藏”,代码更具可读性(恕我直言):

    class ViewController: UIViewController {
    
        @IBOutlet weak var menuView: UIView!
    
        var isMenuVisible = true
    
        @IBAction func handleScreenEdgeGesture(_ gesture: UIScreenEdgePanGestureRecognizer) {
            let translationX = gesture.translation(in: gesture.view!).x
    
            switch gesture.state {
            case .began:
                menuView.transform = CGAffineTransform(translationX: gesture.view!.bounds.width, y: 0)
                menuView.alpha = 1
                fallthrough
    
            case .changed:
                menuView.transform = CGAffineTransform(translationX: gesture.view!.bounds.width + translationX, y: 0)
    
            case .ended:
                let shouldComplete = -translationX > gesture.view!.bounds.width / 2 || gesture.velocity(in: gesture.view!).x < 0
    
                UIView.animate(withDuration: 0.25, delay:0, options: .curveEaseOut, animations: {
                    if shouldComplete {
                        self.menuView.transform = .identity
                        self.isMenuVisible = !self.isMenuVisible
                    } else {
                        self.menuView.transform = CGAffineTransform(translationX: gesture.view!.bounds.width, y: 0)
                    }
                }, completion: { _ in
                    self.menuView.alpha = self.isMenuVisible ? 1 : 0
                })
    
            default:
                break
            }
        }
    
        @IBAction func dragMenu(_ gesture: UIPanGestureRecognizer) {
            let translationX = gesture.translation(in: gesture.view!).x
    
            switch gesture.state {
            case .began, .changed:
                menuView.transform = CGAffineTransform(translationX: translationX, y: 0)
    
            case .ended:
                let shouldComplete = translationX > gesture.view!.bounds.width / 2 || gesture.velocity(in: gesture.view!).x > 0
    
                UIView.animate(withDuration: 0.25, delay:0, options: .curveEaseOut, animations: {
                    if shouldComplete {
                        self.menuView.transform = CGAffineTransform(translationX: gesture.view!.bounds.width, y: 0)
                        self.isMenuVisible = !self.isMenuVisible
                    } else {
                        self.menuView.transform = .identity
                    }
                }, completion: { _ in
                    self.menuView.alpha = self.isMenuVisible ? 1 : 0
                })
    
            default:
                break
            }
        }
    
    }
    
    extension ViewController: UIGestureRecognizerDelegate {
    
        func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
            if gestureRecognizer is UIScreenEdgePanGestureRecognizer {
                return !isMenuVisible
            } else if let gesture = gestureRecognizer as? UIPanGestureRecognizer {
                let translationX = gesture.translation(in: gesture.view!).x
                return isMenuVisible && translationX > 0
            }
    
            return true
        }
    
    }