MBH
MBH

Reputation: 16609

how to prevent view to exceed its parent bounds on Pinch Gesture - swift

I assigned the pinch gesture to uiview:

myView.addGestureRecognizer(UIPinchGestureRecognizer(target: self, action: "handlePinch:"))

This function will scale the uiview:

func handlePinch(recognizer : UIPinchGestureRecognizer) {
    if let view = recognizer.view {
      view.transform = CGAffineTransformScale(view.transform, 
                                recognizer.scale, recognizer.scale)
      recognizer.scale = 1
    }
}

but the scale is not limited within the parent view. and when i try to scale it down it has also no limit, it scales till it disappears.

The grey view is the parent

Desciption

My Question is

How can it be prevented from exceeding the parent frame on scale up and disappearing on scale down?

Upvotes: 2

Views: 1943

Answers (2)

david euler
david euler

Reputation: 824

I wrote a function to test if the pinch is out of parent view's boundary.

/// test if an origin frame scale would be within the boundary of parent view
func scaleWithinBoundary(originFrame:CGRect, parent:UIView, scale:CGFloat) -> Bool {
    let height = originFrame.height * scale
    let width = originFrame.width * scale
    
    let leftX = originFrame.midX - width/2, rightX = originFrame.midX + width/2
    let topY = originFrame.midY - height/2, bottomY = originFrame.midY + height/2
    
    return leftX >= 0 && topY >= 0 && leftX >= parent.frame.minX && rightX <= parent.frame.maxX
        && topY >= parent.frame.minY && bottomY <= parent.frame.maxY
}

Upvotes: 0

treyhakanson
treyhakanson

Reputation: 4911

You could use something like this:

if let view = recognizer.view, parent = recognizer.view.superview {

    // this will only let it scale to half size
    let minimumThreshold: CGFloat = 0.5
    var scale: CGFloat = recognizer.scale

    // assuming your view is square, which based on your example it is
    let newSize = view.frame.height * scale

    // prevents the view from growing larger than the smallest dimension of the parent view
    let allowableSize = min(parent.frame.height, parent.frame.width)
    let maximumScale: CGFloat = allowableSize/view.frame.height

    // change scale if it breaks either bound
    if scale < minimumThreshold {
        print("size is too small")
        scale = minimumThreshold
    }

    if newSize > allowableSize {
        print("size is too large")
        scale = maximumScale
    }

    // apply the transform
    view.transform = CGAffineTransformMakeScale(scale, scale)
}

The key here is to decide on a lower bound based on preference, and an upper bound based on the ratio of your view's initial size to the parent's size. By doing so, the view cannot be shrunk smaller than desired, as assumedly the user should not be able to scale down to a point where they cannot resize due to difficulty pinching. In addition, the view should not be allowed to be scaled infinitely, thus overflowing its bounds. This check does just that, as it allows only a range of sizes you dictate to be set by the user's interactions.

Upvotes: 4

Related Questions