Why does panning let the user move the zoomed view outside the superview?

1.6k Views Asked by At

I am working on pinch in and pinch out feature on pdf pages. My pinch in and panning(moving) is working properly, but when user continuously moves the zoomed view, the zoom view goes outside the super view bounds.Something like this:

theis is the move user made after zoom

how can i limit the pan move so that user could not move the zoomed view/pdf outside the superview.
the relevant code i am using is:

// This method will handle the PINCH / ZOOM gesture 

- (void)pinchZoom:(UIPinchGestureRecognizer *)gestureRecognizer {

    if([gestureRecognizer state] == UIGestureRecognizerStateBegan) {
        // Reset the last scale, necessary if there are multiple objects with different scales
        lastScale = [gestureRecognizer scale];
    }
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {

    if (!zoomActive) {
        zoomActive = YES;
        panActive = YES;
        UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panMove:)];
        [panGesture setMaximumNumberOfTouches:2];
        [panGesture setDelegate:self];
        [self addGestureRecognizer:panGesture];
        [panGesture release];

    }

            CGFloat currentScale = [[[gestureRecognizer view].layer valueForKeyPath:@"transform.scale"] floatValue];

            // Constants to adjust the max/min values of zoom
            const CGFloat kMaxScale = 2.0;
            const CGFloat kMinScale = 1.0;

            CGFloat newScale = 1 -  (lastScale - [gestureRecognizer scale]); 
            newScale = MIN(newScale, kMaxScale / currentScale);   
            newScale = MAX(newScale, kMinScale / currentScale);
            CGAffineTransform transform = CGAffineTransformScale([[gestureRecognizer view] transform], newScale, newScale);
            [gestureRecognizer view].transform = transform;

            lastScale = [gestureRecognizer scale];  // Store the previous scale factor for the next pinch gesture call 



    [delegate leavesView:self zoomingCurrentView:[gestureRecognizer scale]];            




}

}
the method where i am handling the pan move:

// This method will handle the PAN / MOVE gesture 
- (void)panMove:(UIPanGestureRecognizer *)gestureRecognizer  
{  
    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged)   {  
        CGPoint translation = [gestureRecognizer translationInView:[[gestureRecognizer view] superview]];  
        [[gestureRecognizer view] setCenter:CGPointMake([[gestureRecognizer view] center].x + translation.x, [[gestureRecognizer view] center].y + translation.y)];  

        [gestureRecognizer setTranslation:CGPointZero inView:[[gestureRecognizer view] superview]];  
    }  
}  

Please suggest how to handle pan/move limiting panning within its superview bounds.

2

There are 2 best solutions below

1
On

You can add something like this to the code: (This is a little rough so you may have to work out some errors)

if([gestureRecognizer view].frame.bounds.x < self.view.bounds.x - panExapantion)
{ 
    //then don't move it
}

//... repeat this for all sides (this is left), bottom, right, and top.

Edit: Ok, consider a box inside of a boxes, thus we have an inside box and an outer box. If we don't want the inside box to go outside the outer box then we must have all these statements be true:

  1. The moved left side of the inside box is not outside the left side of the outer box.
  2. The moved right side of the inside box is not outside the right side of the outer box.
  3. The moved bottom side of the inside box is not outside the bottom side of the outer box.
  4. The moved top side of the inside box is not outside the top side of the outer box.

In your case the PDF is the inside box and the iPad is the outer box. In order to stop the pdf from going outside the box we need to check if each of these statements is true, and if one is false we do not move the PDF to it's new location OR we move the PDF just near the edge of the iPhone screen.

The problem is if the pinch and zoom is used then the suddenly the box will always be outside the outer box, so how do we fix it? We get how much pixels were added to the inside box when it was zoomed (for the sack of this explanation lets just call this the expansion). So we get how much the box was expanded by and subtract that value. Like so: (This is a dumbed down if statement and will not work in code)

If(outerBox.leftSide is less than innerBox.leftSide - panExpantion) 
{
    //Then the innerBox is outside the outterBox
}

I hoped this helped clarify!

2
On

Try this code in you panMove method. Its working fine in my case.

        static CGPoint initialCenter;

        if (recognizer.state == UIGestureRecognizerStateBegan)
        {
            initialCenter = recognizer.view.center;
        }

        CGPoint translation = [recognizer translationInView:recognizer.view];
        CGPoint newCenter = CGPointMake(initialCenter.x + translation.x,
                                       initialCenter.y + translation.y);
        CGRect newFrame = recognizer.view.frame;
        CGRect superViewBounds = recognizer.view.superview.bounds;
        CGPoint superViewOrigin = recognizer.view.superview.frame.origin;

        if(newCenter.x-(newFrame.size.width/2) >= (superViewBounds.size.width+superViewOrigin.x)-200 /*right*/
           ||
           newCenter.x+(newFrame.size.width/2) <= (superViewOrigin.x+200) /*left*/
           ||
           newCenter.y-(newFrame.size.height/2) >= (superViewBounds.size.height+superViewOrigin.y)-200 /*bottom*/
            ||
            newCenter.y+(newFrame.size.height/2) <= (superViewOrigin.y+100)) /*top*/
        {
            return;
        }else{
            recognizer.view.center = newCenter;
        }