Update constraints with UIPanGestureRecognizer

空扰寡人 提交于 2019-12-11 04:34:45

问题


I have a black separatorView in the middle of the screen separating a topContainerView (orange) and a bottomContainerView (green). The separatorView can be dragged up and down with a panGesture, but I can't get the top and bottom views to update their constraints and resize. The bottom of the orange view and the top of the green view should always stick with the separatorView.

Here's the code I have (UPDATED to include variable declarations):

let separatorView: UIView = {
    let view = UIView()
    view.backgroundColor = UIColor.black
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

let topContainerView : UIView = {
    let view = UIView()
    view.backgroundColor = UIColor.orange
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

let bottomContainerView : UIView = {
    let view = UIView()
    view.backgroundColor = UIColor.green
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

override func viewDidLoad() {
        super.viewDidLoad()
        self.addViews()
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(detectPan(recognizer:)))
        panGesture.delaysTouchesBegan = false
        panGesture.delaysTouchesEnded = false
        separatorView.addGestureRecognizer(panGesture)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func addViews() {
        
        view.addSubview(topContainerView)
        view.addSubview(bottomContainerView)
        view.addSubview(separatorView)
        
        separatorView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        separatorView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        separatorView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        separatorView.heightAnchor.constraint(equalToConstant: 50).isActive = true
        
        topContainerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        topContainerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        topContainerView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        topContainerView.bottomAnchor.constraint(equalTo: separatorView.topAnchor).isActive = true
        
        bottomContainerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        bottomContainerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        bottomContainerView.topAnchor.constraint(equalTo: separatorView.bottomAnchor).isActive = true
        bottomContainerView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    }
    
    func detectPan(recognizer: UIPanGestureRecognizer) {
        let translation = recognizer.translation(in: self.view)
        separatorView.center = CGPoint(x: view.center.x, y: lastLocation.y + translation.y)
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.bringSubview(toFront: separatorView)
        lastLocation = separatorView.center
    }


回答1:


When you are using Autolayout you can't simply modify the frame of elements (which is what you are doing implicitly by changing the center property). Well, you can, but it won't affect any other elements (as you have found) and as soon as Autolayout is triggered your changes to the frame will be reset.

You need to manipulate the constraints so that Autolayout produces the result you want.

In this case you need to modify the constant property of your constraint that ties the separator to the center of the view. You can use the translation value of the pan gesture recognizer to do this. The only tricky bit is that this translation is relative to 0 at the start of the pan, so you need to incorporate any offset from any previous pan.

let separatorView: UIView = {
    let view = UIView()
    view.backgroundColor = UIColor.black
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

let topContainerView : UIView = {
    let view = UIView()
    view.backgroundColor = UIColor.orange
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

let bottomContainerView : UIView = {
    let view = UIView()
    view.backgroundColor = UIColor.green
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

var centerConstraint: NSLayoutConstraint!

var startingConstant: CGFloat  = 0.0

override func viewDidLoad() {
    super.viewDidLoad()
    self.addViews()
    let panGesture = UIPanGestureRecognizer(target: self, action: #selector(detectPan(recognizer:)))
    panGesture.delaysTouchesBegan = false
    panGesture.delaysTouchesEnded = false
    separatorView.addGestureRecognizer(panGesture)
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func addViews() {

    view.addSubview(topContainerView)
    view.addSubview(bottomContainerView)
    view.addSubview(separatorView)

    separatorView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
    separatorView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true

    self.centerConstraint = separatorView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
    self.centerConstraint.isActive = true

    separatorView.heightAnchor.constraint(equalToConstant: 50).isActive = true

    topContainerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
    topContainerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
    topContainerView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
    topContainerView.bottomAnchor.constraint(equalTo: separatorView.topAnchor).isActive = true

    bottomContainerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
    bottomContainerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
    bottomContainerView.topAnchor.constraint(equalTo: separatorView.bottomAnchor).isActive = true
    bottomContainerView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}

func detectPan(recognizer: UIPanGestureRecognizer) {

    switch recognizer.state {
    case .began:
        self.startingConstant = self.centerConstraint.constant
    case .changed:
        let translation = recognizer.translation(in: self.view)
        self.centerConstraint.constant = self.startingConstant + translation.y
    default:
        break
    }
}


来源:https://stackoverflow.com/questions/42077205/update-constraints-with-uipangesturerecognizer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!