约束对象以防止它们在对象改变大小时移动
Constraint objects to prevent them from moving when object changes size
正如您在下面的 gif 中看到的,当幻灯片上深绿色对象的大小增加时,浅绿色对象向南移动。我想要做的是,当深绿色对象的大小增加时,浅绿色对象不会移动它,它只保留在原始位置。即使图像没有移动,同样的事情也会发生。
import UIKit
class ViewController: UIViewController {
var picWidth: NSLayoutConstraint!
var picHeight: NSLayoutConstraint!
var pic = UIImageView()
var slider = UISlider()
var pic2 = UIImageView()
var existingTransition : CGAffineTransform?
var currentView: UIView?
var g2 = UIPanGestureRecognizer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
pic.isUserInteractionEnabled = true
g2 = UIPanGestureRecognizer(target: self, action: #selector(ViewController.g1Method))
pic.addGestureRecognizer(g2)
pic.backgroundColor = .systemGreen
pic2.backgroundColor = .green
picWidth = pic.widthAnchor.constraint(equalTo: view.widthAnchor ,multiplier: 0.2)
picHeight = pic.heightAnchor.constraint(equalTo: view.heightAnchor ,multiplier: 0.20)
[pic,pic2,slider].forEach {
view.addSubview([=10=])
[=10=].translatesAutoresizingMaskIntoConstraints = false
}
NSLayoutConstraint.activate ([
pic.topAnchor.constraint(equalTo: view.topAnchor, constant : 0),
picWidth,
picHeight,
pic.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant :0),
pic2.topAnchor.constraint(equalTo: pic.bottomAnchor, constant : 0),
pic2.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5, constant: 0),
pic2.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.4, constant: 0),
pic2.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
slider.topAnchor.constraint(equalTo: pic2.bottomAnchor, constant : 0),
slider.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.20, constant: 0),
slider.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.20, constant: 0),
slider.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
])
slider.addTarget(self, action: #selector(hhh), for: .allEvents)
}
@objc func handleTapGestured(_ gesture: UIPanGestureRecognizer) {
currentView = gesture.view
}
@objc func g1Method(_ sender: UIPanGestureRecognizer){
let subview = pic2
guard let child = sender.view else{return}
let transitionPoint = sender.translation(in: self.view)
let newTransition = CGAffineTransform(translationX: transitionPoint.x, y: transitionPoint.y)
switch sender.state {
case .ended,.cancelled:// on End
if let existing = existingTransition{
self.existingTransition = newTransition.concatenating(existing)
}else{
self.existingTransition = newTransition
}
default://on change and other states
if let existing = existingTransition{
child.transform = newTransition
.concatenating(existing)
}else{
child.transform = newTransition
}
}
self.view.layoutIfNeeded()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGestured(_:)))
subview.addGestureRecognizer(tapGesture)
}
@objc func hhh() {
picWidth.constant = CGFloat(slider.value) * view.frame.size.width * 0.25
picHeight.constant = CGFloat(slider.value) * view.frame.size.height * 0.25
}
}
你的问题出在这里:
pic2.topAnchor.constraint(equalTo: pic.bottomAnchor, constant : 0)
您是在告诉布局保持 pic2
形状的顶部与 pic
形状的底部相同。
要解决此问题,请将 pic2
约束到顶部安全 space,然后将 pic
的高度作为常数,将 pic2
的顶部直接放在 pic
.
pic2.topAnchor.constraint(equalTo: view.topAnchor, constant : pic.bounds.height)
编辑:pic.bounds.height
不会加载,因为您正在同时加载 viewDidLoad 中的约束并且 ViewController 尚未放置子视图,因此您的 pic
在调用 pic.bounds.height
时为空。为了解决这个问题,您需要执行以下操作:
•隔离viewDidLoad中的pic初始化:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
pic.isUserInteractionEnabled = true
g2 = UIPanGestureRecognizer(target: self, action: #selector(ViewController.g1Method))
pic.addGestureRecognizer(g2)
pic.backgroundColor = .systemGreen
pic2.backgroundColor = .green
picWidth = pic.widthAnchor.constraint(equalTo: view.widthAnchor ,multiplier: 0.2)
picHeight = pic.heightAnchor.constraint(equalTo: view.heightAnchor ,multiplier: 0.20)
[pic,pic2,slider].forEach {
view.addSubview([=10=])
[=10=].translatesAutoresizingMaskIntoConstraints = false
}
NSLayoutConstraint.activate([pic.topAnchor.constraint(equalTo: view.topAnchor, constant : 0),
picWidth,
picHeight,
pic.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant :0)])
slider.addTarget(self, action: #selector(hhh), for: .allEvents)
}
•把剩下的inits扔进viewDidLayoutSubviews:
override func viewDidLayoutSubviews() {
NSLayoutConstraint.activate ([
pic2.topAnchor.constraint(equalTo: view.topAnchor, constant : pic.bounds.height),
pic2.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5, constant: 0),
pic2.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.4, constant: 0),
pic2.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
slider.topAnchor.constraint(equalTo: pic2.bottomAnchor, constant : 0),
slider.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.20, constant: 0),
slider.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.20, constant: 0),
slider.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
])
}
附带说明一下,如果您要移动浅绿色方块,滑块仍然会乱七八糟,因为您将其限制在方块内。尝试采用基于视图锚点而非其他 UI 元素对位于屏幕外部的对象进行约束的模式。
正如您在下面的 gif 中看到的,当幻灯片上深绿色对象的大小增加时,浅绿色对象向南移动。我想要做的是,当深绿色对象的大小增加时,浅绿色对象不会移动它,它只保留在原始位置。即使图像没有移动,同样的事情也会发生。
import UIKit
class ViewController: UIViewController {
var picWidth: NSLayoutConstraint!
var picHeight: NSLayoutConstraint!
var pic = UIImageView()
var slider = UISlider()
var pic2 = UIImageView()
var existingTransition : CGAffineTransform?
var currentView: UIView?
var g2 = UIPanGestureRecognizer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
pic.isUserInteractionEnabled = true
g2 = UIPanGestureRecognizer(target: self, action: #selector(ViewController.g1Method))
pic.addGestureRecognizer(g2)
pic.backgroundColor = .systemGreen
pic2.backgroundColor = .green
picWidth = pic.widthAnchor.constraint(equalTo: view.widthAnchor ,multiplier: 0.2)
picHeight = pic.heightAnchor.constraint(equalTo: view.heightAnchor ,multiplier: 0.20)
[pic,pic2,slider].forEach {
view.addSubview([=10=])
[=10=].translatesAutoresizingMaskIntoConstraints = false
}
NSLayoutConstraint.activate ([
pic.topAnchor.constraint(equalTo: view.topAnchor, constant : 0),
picWidth,
picHeight,
pic.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant :0),
pic2.topAnchor.constraint(equalTo: pic.bottomAnchor, constant : 0),
pic2.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5, constant: 0),
pic2.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.4, constant: 0),
pic2.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
slider.topAnchor.constraint(equalTo: pic2.bottomAnchor, constant : 0),
slider.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.20, constant: 0),
slider.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.20, constant: 0),
slider.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
])
slider.addTarget(self, action: #selector(hhh), for: .allEvents)
}
@objc func handleTapGestured(_ gesture: UIPanGestureRecognizer) {
currentView = gesture.view
}
@objc func g1Method(_ sender: UIPanGestureRecognizer){
let subview = pic2
guard let child = sender.view else{return}
let transitionPoint = sender.translation(in: self.view)
let newTransition = CGAffineTransform(translationX: transitionPoint.x, y: transitionPoint.y)
switch sender.state {
case .ended,.cancelled:// on End
if let existing = existingTransition{
self.existingTransition = newTransition.concatenating(existing)
}else{
self.existingTransition = newTransition
}
default://on change and other states
if let existing = existingTransition{
child.transform = newTransition
.concatenating(existing)
}else{
child.transform = newTransition
}
}
self.view.layoutIfNeeded()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGestured(_:)))
subview.addGestureRecognizer(tapGesture)
}
@objc func hhh() {
picWidth.constant = CGFloat(slider.value) * view.frame.size.width * 0.25
picHeight.constant = CGFloat(slider.value) * view.frame.size.height * 0.25
}
}
你的问题出在这里:
pic2.topAnchor.constraint(equalTo: pic.bottomAnchor, constant : 0)
您是在告诉布局保持 pic2
形状的顶部与 pic
形状的底部相同。
要解决此问题,请将 pic2
约束到顶部安全 space,然后将 pic
的高度作为常数,将 pic2
的顶部直接放在 pic
.
pic2.topAnchor.constraint(equalTo: view.topAnchor, constant : pic.bounds.height)
编辑:pic.bounds.height
不会加载,因为您正在同时加载 viewDidLoad 中的约束并且 ViewController 尚未放置子视图,因此您的 pic
在调用 pic.bounds.height
时为空。为了解决这个问题,您需要执行以下操作:
•隔离viewDidLoad中的pic初始化:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
pic.isUserInteractionEnabled = true
g2 = UIPanGestureRecognizer(target: self, action: #selector(ViewController.g1Method))
pic.addGestureRecognizer(g2)
pic.backgroundColor = .systemGreen
pic2.backgroundColor = .green
picWidth = pic.widthAnchor.constraint(equalTo: view.widthAnchor ,multiplier: 0.2)
picHeight = pic.heightAnchor.constraint(equalTo: view.heightAnchor ,multiplier: 0.20)
[pic,pic2,slider].forEach {
view.addSubview([=10=])
[=10=].translatesAutoresizingMaskIntoConstraints = false
}
NSLayoutConstraint.activate([pic.topAnchor.constraint(equalTo: view.topAnchor, constant : 0),
picWidth,
picHeight,
pic.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant :0)])
slider.addTarget(self, action: #selector(hhh), for: .allEvents)
}
•把剩下的inits扔进viewDidLayoutSubviews:
override func viewDidLayoutSubviews() {
NSLayoutConstraint.activate ([
pic2.topAnchor.constraint(equalTo: view.topAnchor, constant : pic.bounds.height),
pic2.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5, constant: 0),
pic2.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.4, constant: 0),
pic2.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
slider.topAnchor.constraint(equalTo: pic2.bottomAnchor, constant : 0),
slider.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.20, constant: 0),
slider.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.20, constant: 0),
slider.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
])
}
附带说明一下,如果您要移动浅绿色方块,滑块仍然会乱七八糟,因为您将其限制在方块内。尝试采用基于视图锚点而非其他 UI 元素对位于屏幕外部的对象进行约束的模式。