Restrict movement of shape to dimensions of UIImageView

145 views Asked by At

Using some code I came across that draws a circle shape over an image. Pan and pinch gestures are used on the circle shape being drawn. The movement of the shape crosses over the dimensions of the UIImageView, onto the rest of the UI that is not displaying the image. I've tried to incorporate methods used in other examples where pan and pinch restrictions were needed in order to restrict the circle shape's movement to the bounds of the UIImageView, but could not get any of them to work. I understand that I would need to control the center and radius values of the pan and pinch so that they don't cross outside the UIImageView's border, but haven't the slightest clue as to how to execute this. Attached is the code I'm using. Thanks for your help!

-(void)setUpCropTool:(id)sender{

    // create layer mask for the image

    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    self.imageToBeCropped.layer.mask = maskLayer;
    self.maskLayer = maskLayer;

    // create shape layer for circle we'll draw on top of image (the boundary of the circle)

    CAShapeLayer *circleLayer = [CAShapeLayer layer];
    circleLayer.lineWidth = 50;
    circleLayer.fillColor = [[UIColor clearColor] CGColor];
    circleLayer.strokeColor = [[UIColor redColor] CGColor];
    [self.imageToBeCropped.layer addSublayer:circleLayer];
    self.circleLayer = circleLayer;

    // create circle path

    [self updateCirclePathAtLocation:CGPointMake(self.imageToBeCropped.bounds.size.width / 2.0, self.imageToBeCropped.bounds.size.height / 2.0) radius:self.imageToBeCropped.bounds.size.width/2.5];

    // create pan gesture

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
    pan.delegate = self;
    [self.imageToBeCropped addGestureRecognizer:pan];
    self.imageToBeCropped.userInteractionEnabled = YES;
    self.pan = pan;

    // create pan gesture

    UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];
    pinch.delegate = self;
    [self.imageToBeCropped addGestureRecognizer:pinch];
    self.pinch = pinch;

}

- (void)updateCirclePathAtLocation:(CGPoint)location radius:(CGFloat)radius
{
    self.circleCenter = location;
    self.circleRadius = radius;

    UIBezierPath *path = [UIBezierPath bezierPath];
    [path addArcWithCenter:self.circleCenter
                    radius:self.circleRadius
                startAngle:0.0
                  endAngle:M_PI * 2.0
                 clockwise:YES];

    self.maskLayer.path = [path CGPath];
    self.circleLayer.path = [path CGPath];
}

#pragma mark - Gesture recognizers

- (void)handlePan:(UIPanGestureRecognizer *)gesture
{
    static CGPoint oldCenter;
    CGPoint tranlation = [gesture translationInView:gesture.view];

    if (gesture.state == UIGestureRecognizerStateBegan)
    {
        oldCenter = self.circleCenter;
    }

    CGPoint newCenter = CGPointMake(oldCenter.x + tranlation.x, oldCenter.y + tranlation.y);



        [self updateCirclePathAtLocation:newCenter radius:self.circleRadius];



}

- (void)handlePinch:(UIPinchGestureRecognizer *)gesture
{
    static CGFloat oldRadius;
    CGFloat scale = [gesture scale];

    if (gesture.state == UIGestureRecognizerStateBegan)
    {
        oldRadius = self.circleRadius;
    }

    CGFloat newRadius = oldRadius * scale;

    [self updateCirclePathAtLocation:self.circleCenter radius:newRadius];
}


#pragma mark - UIGestureRecognizerDelegate

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    if ((gestureRecognizer == self.pan   && otherGestureRecognizer == self.pinch) ||
        (gestureRecognizer == self.pinch && otherGestureRecognizer == self.pan))
    {
        return YES;
    }

    return NO;
}
1

There are 1 answers

0
Snacks On

Try adding some additional constraints to the pan handling code. Maybe something like:

if (oldCenter.x + tranlation.x >= superView.frame.size.width - self.circleRadius
|| oldCenter.x + tranlation.x <= self.circleRadius)
{
    newCenter.x = oldCenter.x;
}
else
{
    newCenter.x = oldCenter.x + tranlation.x;
}

This is a pretty simple example, hope it helps.