My swift code as you can see in the gif below. Lets the user select one of the image views then use the slider to increase or decrease the size of that image view. The problem is when the image view is moved the other image view follows it that should not happen. So the constraints should be set when the code runs for the first time but after one of the imageviews is selected. The constraints linking them together should become deactivated. A line causing this is
** greenMove.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant :0),**
import UIKit
class ViewController: UIViewController {
var image1Width: NSLayoutConstraint!
var image1Height: NSLayoutConstraint!
var image1Width2: NSLayoutConstraint!
var image1Height2: NSLayoutConstraint!
var greenMove = UIImageView()
var slider = UISlider()
var blueMove = UIImageView()
var existingTransition : CGAffineTransform?
var clock = Int()
var currentView: UIView?
var g2 = UIPanGestureRecognizer()
var g3 = UIPanGestureRecognizer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
greenMove.isUserInteractionEnabled = true
blueMove.isUserInteractionEnabled = true
g2 = UIPanGestureRecognizer(target: self, action: #selector(ViewController.g1Method))
greenMove.addGestureRecognizer(g2)
g3 = UIPanGestureRecognizer(target: self, action: #selector(ViewController.g2Method))
blueMove.addGestureRecognizer(g3)
greenMove.backgroundColor = .systemGreen
blueMove.backgroundColor = .blue
[greenMove,slider,blueMove].forEach {
view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
//image11
image1Width = greenMove.widthAnchor.constraint(equalTo: view.widthAnchor ,multiplier: 0.2)
image1Height = greenMove.heightAnchor.constraint(equalTo: view.heightAnchor ,multiplier: 0.20)
//image12
image1Width2 = blueMove.widthAnchor.constraint(equalTo: view.widthAnchor ,multiplier: 0.2)
image1Height2 = blueMove.heightAnchor.constraint(equalTo: view.heightAnchor ,multiplier: 0.20)
NSLayoutConstraint.activate([
greenMove.topAnchor.constraint(equalTo: view.topAnchor, constant : 0),
image1Width,
image1Height,
greenMove.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant :0),
blueMove.topAnchor.constraint(equalTo: view.topAnchor, constant : 0),
image1Width2,
image1Height2,
blueMove.leadingAnchor.constraint(equalTo: greenMove.trailingAnchor, constant :0)
])
slider.addTarget(self, action: #selector(hhh), for: .allEvents)
}
override func viewDidLayoutSubviews() {
NSLayoutConstraint.activate ([
slider.topAnchor.constraint(equalTo: view.topAnchor, constant : greenMove.bounds.height),
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),
])
}
@objc func handleTapGestured(_ gesture: UIPanGestureRecognizer) {
currentView = gesture.view
}
@objc func g1Method(_ sender: UIPanGestureRecognizer){
clock = 1
let subview = greenMove
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 g2Method(_ sender: UIPanGestureRecognizer){
clock = 2
let subview = blueMove
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() {
if clock == 1 {
image1Width.constant = CGFloat(slider.value) * view.frame.size.width * 0.25
image1Height.constant = CGFloat(slider.value) * view.frame.size.height * 0.25
}
if clock == 2 {
image1Width2.constant = CGFloat(slider.value) * view.frame.size.width * 0.25
image1Height2.constant = CGFloat(slider.value) * view.frame.size.height * 0.25
}
}
}
The problem you are running into is because you are using a single transform for both views and concatenating new transform information that gets applied to the other view when you try to move it.
Make these changes to your posted code...
At the class level, create separate transform "trackers":
// don't use this
//var existingTransition : CGAffineTransform?
// separate transforms for each "move view"
var blueTransition: CGAffineTransform?
var greenTransition: CGAffineTransform?
Then, in g1Method
and g2Method
use the associated transform:
@objc func g1Method(_ sender: UIPanGestureRecognizer){
clock = 1
let subview = greenMove
guard let child = sender.view else{return}
let transitionPoint = sender.translation(in: self.view)
let newTransition = CGAffineTransform(translationX: transitionPoint.x, y: transitionPoint.y)
// greenMove view must track its own CGAffineTransform
switch sender.state {
case .ended,.cancelled:// on End
if let existing = greenTransition {
greenTransition = newTransition.concatenating(existing)
} else {
greenTransition = newTransition
}
//if let existing = existingTransition{
// self.existingTransition = newTransition.concatenating(existing)
//}else{
// self.existingTransition = newTransition
//}
default://on change and other states
if let existing = greenTransition {
child.transform = newTransition
.concatenating(existing)
} else {
child.transform = newTransition
}
//if let existing = existingTransition{
// child.transform = newTransition
// .concatenating(existing)
//}else{
// child.transform = newTransition
//}
}
self.view.layoutIfNeeded()
// move this to viewDidLoad(), otherwise you are adding ANOTHER recognizer each time this method is called
//let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGestured(_:)))
//subview.addGestureRecognizer(tapGesture)
}
@objc func g2Method(_ sender: UIPanGestureRecognizer){
clock = 2
let subview = blueMove
guard let child = sender.view else{return}
let transitionPoint = sender.translation(in: self.view)
let newTransition = CGAffineTransform(translationX: transitionPoint.x, y: transitionPoint.y)
// blueMove view must track its own CGAffineTransform
switch sender.state {
case .ended,.cancelled:// on End
if let existing = blueTransition {
blueTransition = newTransition.concatenating(existing)
} else {
blueTransition = newTransition
}
//if let existing = existingTransition{
// self.existingTransition = newTransition.concatenating(existing)
//}else{
// self.existingTransition = newTransition
//}
default://on change and other states
if let existing = blueTransition {
child.transform = newTransition
.concatenating(existing)
} else {
child.transform = newTransition
}
//if let existing = existingTransition{
// child.transform = newTransition
// .concatenating(existing)
//}else{
// child.transform = newTransition
//}
}
self.view.layoutIfNeeded()
// move this to viewDidLoad(), otherwise you are adding ANOTHER recognizer each time this method is called
//let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGestured(_:)))
//subview.addGestureRecognizer(tapGesture)
}