I have one imageview which has 2 gestureRecognizers 1)Pinch 2)Pan
I am able to pinch an image and zoom using scale property what I am not able to achieve is that when I zoom that image and drag to all 4 sides I can drag image and I am able to see the background view behind the imageview want to restrict drag of the imageview till that zommed image is shown
Here is the code for pinch and pan gesture
@objc func pinchRecognized(pinch: UIPinchGestureRecognizer) {
if let view = pinch.view {
view.transform = view.transform.scaledBy(x: pinch.scale, y: pinch.scale)
pinch.scale = 1
}
}
@objc func PangestureMethod(gestureRecognizer: UIPanGestureRecognizer){
guard gestureRecognizer.view != nil else {return}
let piece = gestureRecognizer.view!
let translation = gestureRecognizer.translation(in: piece.superview)
if gestureRecognizer.state == .began {
self.initialCenter = piece.center
}
if gestureRecognizer.state != .cancelled {
let newCenter = CGPoint(x: initialCenter.x + translation.x, y: initialCenter.y + translation.y)
piece.center = newCenter
}
else {
piece.center = initialCenter
}
}
First, it's (probably) easier to reset the Pan Gesture's Translation so we're calculating relative movement:
if gestureRecognizer.state != .cancelled {
// translation will be + or - a small number of points
// do what's needed to move the view
// reset recognizer
gestureRecognizer.setTranslation(.zero, in: superV)
}
Otherwise, let's say you drag (pan) right 300-pts, but the view can only move 20-pts, then it won't start moving back to the left until you've dragged 280-pts left.
So, when dragging horizontally and we want to stop when the drag-view is at the left or right edge of its superView...
As an example, if the superView's width is 100
, and the drag-view's width is 200
, the MAX centerX will be 100
and the MIN centerX will be Zero
.
Then we do the same thing for the centerY position.
Try using this as your Pan Gesture handler:
@objc func PangestureMethod(gestureRecognizer: UIPanGestureRecognizer){
// unwrap the view from the gesture
// AND
// unwrap that view's superView
guard let piece = gestureRecognizer.view,
let superV = piece.superview
else {
return
}
let translation = gestureRecognizer.translation(in: superV)
if gestureRecognizer.state == .began {
self.initialCenter = piece.center
}
if gestureRecognizer.state != .cancelled {
// what the new centerX and centerY will be
var newX: CGFloat = piece.center.x + translation.x
var newY: CGFloat = piece.center.y + translation.y
// MAX centerX is 1/2 the width of the piece's frame
let mxX = piece.frame.width * 0.5
// MIN centerX is Width of superView minus 1/2 the width of the piece's frame
let mnX = superV.bounds.width - piece.frame.width * 0.5
// make sure new centerX is neither greater than MAX nor less than MIN
newX = max(min(newX, mxX), mnX)
// MAX centerY is 1/2 the height of the piece's frame
let mxY = piece.frame.height * 0.5
// MIN centerY is Height of superView minus 1/2 the height of the piece's frame
let mnY = superV.bounds.height - piece.frame.height * 0.5
// make sure new centerY is neither greater than MAX nor less than MIN
newY = max(min(newY, mxY), mnY)
// set the new center
piece.center = CGPoint(x: newX, y: newY)
// reset recognizer
gestureRecognizer.setTranslation(.zero, in: superV)
}
else {
piece.center = initialCenter
}
}
Edit
To prevent the Pinch Gesture from scaling down the view to smaller than its superView frame, we can apply the new scale value from the gesture to a CGRect
of the view's frame before applying it to the view.
Then, only apply the scaling to the view if the resulting rect would not be smaller than the superView's frame.
Give this a try:
@objc func pinchRecognized(pinch: UIPinchGestureRecognizer) {
// unwrap the view from the gesture
// AND
// unwrap that view's superView
guard let piece = pinch.view,
let superV = piece.superview
else {
return
}
// this is a bit verbose for clarity
// get the new scale
let sc = pinch.scale
// get current frame of "piece" view
let currentPieceRect = piece.frame
// apply scaling transform to the rect
let futureRect = currentPieceRect.applying(CGAffineTransform(scaleX: sc, y: sc))
// if the resulting rect's width will be
// greater-than-or-equal to superView's width
if futureRect.width >= superV.bounds.width {
// go ahead and scale the piece view
piece.transform = piece.transform.scaledBy(x: sc, y: sc)
}
pinch.scale = 1
}