As you can see in the gif below the light green objects moves south when the size of the dark green object is increased on the slide. What I want to do is when the dark green object size is increased the light green object does not move it all it remains at is original position. Even if the image does not move the same thing happens.
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($0)
$0.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
}
}
Your problem lies here:
pic2.topAnchor.constraint(equalTo: pic.bottomAnchor, constant : 0)
You are telling the layout to keep the top of your pic2
shape equivalent to the bottom of your pic
shape.
To fix this, constrain pic2
to the top safe space, then the height of pic
as the constant to put the top of pic2
directly under pic
.
pic2.topAnchor.constraint(equalTo: view.topAnchor, constant : pic.bounds.height)
Edit: pic.bounds.height
won't load because you are loading the constraints in the viewDidLoad all at the same time and the ViewController hasn't laid subviews yet, thus your pic
is null when pic.bounds.height
is called. In order to fix this issue, you need to do the following:
•Isolate the pic initialization in viewDidLoad:
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($0)
$0.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)
}
•Throw the rest of the inits into 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),
])
}
As a side note, the slider would still be messed up if you were to make the light green square move because you are constraining it to the square. Try to get in the pattern of making your constraints for object located on the outer parts of the screen based off of the view's anchors, not other UI elements.