I've been doing this small app that contains a UIImageView. I can tap on it and 4 circles on each corner of the image should appear. I have to be able to drag my finger from the corner to resize the image. However the resizing doesn't work. From what I understood - I have to update the constraints of the imageView in the touchesMoved method.
I was using this post as a reference: How to resize UIView by dragging from its edges?
Setup imageView, scrollView and buttons
struct ResizeRect{
var topTouch = false
var leftTouch = false
var rightTouch = false
var bottomTouch = false
var middelTouch = false
}
This is for my circles on the corners
private var topLeftCircleLayer: CAShapeLayer!
private var topRightCircleLayer: CAShapeLayer!
private var bottomLeftCircleLayer: CAShapeLayer!
private var bottomRightCircleLayer: CAShapeLayer!
Constraints for imageView
private var imageViewTopConstraint: NSLayoutConstraint!
private var imageViewBottomConstraint: NSLayoutConstraint!
private var imageViewLeadingConstraint: NSLayoutConstraint!
private var imageViewTrailingConstraint: NSLayoutConstraint!
private var originalImageFrame: CGRect = .zero
private var resizeRect = ResizeRect()
Setting up my views
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
setupView()
addTapGestureRecognizer()
addPinchGestureRecognizer()
addRotateButton()
addDeletePhotoButton()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
borderLayer.path = UIBezierPath(rect: imageView.bounds).cgPath
addConstraintsForItems()
createCircles()
}
private func addConstraintsForItems() {
imageViewTopConstraint = imageView.topAnchor.constraint(equalTo: view.topAnchor, constant: 180)
imageViewBottomConstraint = imageView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -180)
imageViewLeadingConstraint = imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 70)
imageViewTrailingConstraint = imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -70)
NSLayoutConstraint.activate([imageViewTopConstraint, imageViewBottomConstraint, imageViewLeadingConstraint, imageViewTrailingConstraint])
}
private func setupView() {
view.addSubview(scrollView)
view.addSubview(rotateButton)
view.addSubview(deleteButton)
scrollView.addSubview(imageView)
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.strokeColor = UIColor.black.cgColor
borderLayer.lineWidth = 2
borderLayer.isHidden = true
imageView.layer.addSublayer(borderLayer)
}
Circle creation
private func updateCircles() {
let topLeft = CGPoint(x: imageView.frame.minX, y: imageView.frame.minY)
topLeftCircleLayer.position = topLeft
let topRight = CGPoint(x: imageView.frame.maxX, y: imageView.frame.minY)
topRightCircleLayer.position = topRight
let bottomLeft = CGPoint(x: imageView.frame.minX, y: imageView.frame.maxY)
bottomLeftCircleLayer.position = bottomLeft
let bottomRight = CGPoint(x: imageView.frame.maxX, y: imageView.frame.maxY)
bottomRightCircleLayer.position = bottomRight
imageView.layer.insertSublayer(topLeftCircleLayer, at: 0)
imageView.layer.insertSublayer(topRightCircleLayer, at: 1)
imageView.layer.insertSublayer(bottomLeftCircleLayer, at: 2)
imageView.layer.insertSublayer(bottomRightCircleLayer, at: 3)
}
private func createCircles() {
topLeftCircleLayer = createCircle(at: CGPoint(x: imageView.frame.minX, y: imageView.frame.minY))
topRightCircleLayer = createCircle(at: CGPoint(x: imageView.frame.maxX, y: imageView.frame.minY))
bottomLeftCircleLayer = createCircle(at: CGPoint(x: imageView.frame.minX, y: imageView.frame.maxY))
bottomRightCircleLayer = createCircle(at: CGPoint(x: imageView.frame.maxX, y: imageView.frame.maxY))
}
private func createCircle(at position: CGPoint) -> CAShapeLayer {
let circle = CAShapeLayer()
circle.path = UIBezierPath(arcCenter: position, radius: 10, startAngle: 0, endAngle: .pi * 2, clockwise: true).cgPath
circle.fillColor = UIColor.systemPink.cgColor
circle.strokeColor = UIColor.white.cgColor
circle.lineWidth = 6
circle.isHidden = !isCirclesVisible
imageView.layer.addSublayer(circle)
return circle
}
And this is the most important part where I try to drag the corner
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first{
let touchStart = touch.location(in: self.view)
print(touchStart)
resizeRect.topTouch = false
resizeRect.leftTouch = false
resizeRect.rightTouch = false
resizeRect.bottomTouch = false
if touchStart.y > imageView.frame.maxY - proxyFactor && touchStart.y < imageView.frame.maxY + proxyFactor {
resizeRect.bottomTouch = true
print("bottom")
}
if touchStart.x > imageView.frame.maxX - proxyFactor && touchStart.x < imageView.frame.maxX + proxyFactor {
resizeRect.rightTouch = true
print("right")
}
if touchStart.x > imageView.frame.minX - proxyFactor && touchStart.x < imageView.frame.minX + proxyFactor {
resizeRect.leftTouch = true
print("left")
}
if touchStart.y > imageView.frame.minY - proxyFactor && touchStart.y < imageView.frame.minY + proxyFactor {
resizeRect.topTouch = true
print("top")
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first{
let currentTouchPoint = touch.location(in: self.view)
let previousTouchPoint = touch.previousLocation(in: self.view)
let deltaX = currentTouchPoint.x - previousTouchPoint.x
let deltaY = currentTouchPoint.y - previousTouchPoint.y
if resizeRect.topTouch && resizeRect.leftTouch {
if imageViewTopConstraint.constant + deltaY > 0 && imageViewLeadingConstraint.constant + deltaX > 0 {
imageViewTopConstraint.constant += deltaY
imageViewLeadingConstraint.constant += deltaX
}
}
if resizeRect.topTouch && resizeRect.rightTouch {
if imageViewTopConstraint.constant + deltaY > 0 && imageViewTrailingConstraint.constant - deltaX > 0 {
imageViewTopConstraint.constant += deltaY
imageViewTrailingConstraint.constant -= deltaX
}
}
if resizeRect.bottomTouch && resizeRect.leftTouch {
if imageViewBottomConstraint.constant - deltaY > 0 && imageViewLeadingConstraint.constant + deltaX > 0 {
imageViewLeadingConstraint.constant += deltaX
imageViewBottomConstraint.constant -= deltaY
}
}
if resizeRect.bottomTouch && resizeRect.rightTouch {
if imageViewBottomConstraint.constant - deltaY > 0 && imageViewTrailingConstraint.constant - deltaX > 0 {
imageViewTrailingConstraint.constant -= deltaX
imageViewBottomConstraint.constant -= deltaY
}
}
UIView.animate(withDuration: 0.25, delay: 0, options: UIView.AnimationOptions.curveEaseIn) {
self.view.layoutIfNeeded()
}
}
}
Edit 1: I've updated my code a bit. My app finally understands when I touch the imageView, when I touch a corner it can say which corner was touched but resizing doesn't work properly. Sometimes it works but it does the resizing very slowly. In the console it says that I have this error:
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x600000cf8910 H:|-(65)-[UIImageView:0x13a707300] (active, names: '|':UIView:0x13c20f220 )>",
"<NSLayoutConstraint:0x600000ce0640 H:|-(70)-[UIImageView:0x13a707300] (active, names: '|':UIView:0x13c20f220 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600000ce0640 H:|-(70)-[UIImageView:0x13a707300] (active, names: '|':UIView:0x13c20f220 )>
I try to update the constraints but for some reason it won't let me. I've cloned the github project from a person that wrote a solution. He made IBOutlets for constraints and from what I understand - constraints created from IBOutlets are some kind different from those that I have. How do I fix the constraint issue? And I would be very grateful if someone could notice what is wrong with my circle creation. Right now I only see 1 below the middle of the image...