使用 UIPanGestureRecognizer 更新约束 [英] Update constraints with UIPanGestureRecognizer
问题描述
我在屏幕中间有一个黑色的 separatorView,将一个 topContainerView(橙色)和一个 bottomContainerView(绿色)分开.separatorView 可以使用 panGesture 上下拖动,但我无法获取顶部和底部视图来更新其约束和调整大小.橙色视图的底部和绿色视图的顶部应始终与 separatorView 保持一致.
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
}
推荐答案
当您使用 Autolayout 时,您不能简单地修改元素的框架(这是您通过更改 center
财产).好吧,您可以,但它不会影响任何其他元素(如您所见),并且一旦触发自动布局,您对框架的更改将被重置.
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.
您需要操纵约束,以便 Autolayout 产生您想要的结果.
You need to manipulate the constraints so that Autolayout produces the result you want.
在这种情况下,您需要修改约束的 constant
属性,将分隔符与视图的中心联系起来.您可以使用平移手势识别器的翻译值来执行此操作.唯一棘手的一点是,此转换相对于平移开始时的 0,因此您需要合并任何先前平移的偏移量.
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
}
}
这篇关于使用 UIPanGestureRecognizer 更新约束的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!