Question

I am looking to alter an existing iOS application so that instead of using multi-touch gestures to size and rotate images (two-finger pinch/zoom and twist), I want there to be a handle on all four corners of the image and one at the top so that the user can grab one of the handles to re-size or rotate.

I have been researching the topic but am unable to find anything pointing me in the right direction.

See this image for an example of what I'm talking about-

i1220.photobucket.com/albums/dd444/mcthompson1/ImageUI_zpsb320417c.png

Was it helpful?

Solution

I'm assuming that because you're starting with a app that already has working pinch-zoom and twist gestures that your question is merely how to show those translucent circles for the handles. I'd be inclined to create UIView subclass that draws the circle, like so:

@implementation HandleView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor clearColor];
        self.userInteractionEnabled = YES;
    }
    return self;
}

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextAddEllipseInRect(context, rect);
    CGContextSetFillColorWithColor(context, [[UIColor colorWithWhite:1.0 alpha:0.5] CGColor]);    // white translucent
    CGContextSetStrokeColorWithColor(context, [[UIColor colorWithWhite:0.25 alpha:0.5] CGColor]); // dark gray translucent
    CGContextSetLineWidth(context, 1.0);
    CGContextDrawPath(context, kCGPathEOFillStroke); // draw both fill and stroke
}

@end

You could achieve the same effect with CAShapeLayer layers, too, if you didn't want to write your own drawRect with Core Graphics calls like I did above. But the idea would be the same.

Your view controller can then add those five views and add gesture recognizers for them, like so:

HandleView *handleView = [[HandleView alloc] initWithFrame:CGRectMake(50, 50, 50, 50)];
[self.view addSubview:handleView];
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
[handleView addGestureRecognizer:pan];

Just repeat that for each of the handles you want on the screen. and then write your gesture recognizer to do whatever you want (e.g. move the bounding rectangle, move the appropriate handles, etc.).

OTHER TIPS

Sounds fairly straight forward. The view hierarchy of one possible solution as ASCII art:

Container (ScalingRotatingView)
  |
  +----imageView (UIImageView)
  |
  +----upperLeftScalingHandle (HandleView)
  |
  +----upperRightScalingHandle (HandleView)
  |
  +----lowerLeftScalingHandle (HandleView)
  |
  +----lowerRightScalingHandle (HandleView)
  |
  +----rotatingHandle (HandleView)

All instances of HandleView would have a pan gesture recognizer, that feeds one of two methods in your controller:

--updateForScaleGesture:, where you’d use the gesture recognizer’s -translationInView: to compute and store the new scale, before updating the frames of all views appropriately, and resetting the translation to 0, and - -updateForRotationGesture:, where you’d use the gesture recognizer’s -translationInView: to compute and store the new angle before updating the frames and resetting the recognizer’s translation.

For both calculations you need the translation in the coordinate system of the image view. For the scaling part, you can then simply divide the new edge lengths by the natural image dimensions, for the rotation you can use the approximation that only the x component of the translation matters:

sin(x) = x (for small values of x)

Oh, and it sure helps if the anchor point of your image view sits at its center…

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top