Question

I currently have an application where a user takes a photo or chooses from their library.

On the next controller it will show the image that was selected/taken.

What I would like to do now is show a view of some sort on top of the image view. The view would be translucent round the edges and have a circle which would show the image beneath (not transulcent). Basically this is selected a part of the image.

I then need to save some how where the view is on screen, as it should also be moveable by the user.

What is the best way to approach this?

I need an overlay view which can be moved. The circle would be a fixed size always the inside shows the imageview beneath and the outside would be a 0.5 translucency so you can still see the image but not completely. Then to save the location of the moved around circle?

---- EDIT ----- enter image description here

This is the example image I have created.

I have a view which has a photo as the UIImageView (bottom layer). On top of this I am trying to add a view (like the picture above). Note, the picture above is actually a png as suggested. However, this overlay is moveable. The circle is transparent (0) so you can completely see the photo below it. The outer (grey) is transparent partially (0.5) so you can still see just not completely.

The top view (circle part) would be moved around on the photo to mark a specific point on the photo. In this example if the circle is moved the side (grey) ends on screen, therefore I would need to make a huge image which takes into account the moving of the view -- which is not the best way to do this surely?

EDIT 2 ---- I now have one UIImageView over the top of the photoView (another UIImageView). The overlay is 4 times the screen with a circle in the middle of it.

When the item is moved I have a gesture recognizer that runs:

-(void)handlePan:(UIPanGestureRecognizer *)gesture {
    NSLog(@"Pan Gesture");
    gesture.view.center = [gesture locationInView:self.view];
   }

At present from the above the UIImageView is moved from the middle point, that way the circle is what looks to be moving when the finger moves.

That is all great, but how do I implement the suggested answers into my handlePan method. So I need to check that the middle point is not too close the edge. Ideally I would like a 50 margin around the screen so the circle does not look to go completely (or mostly) off screen?

Was it helpful?

Solution

I understand from the question that you know how to do the movement of the overlay, so what I meant is just that you can simply use image views big enough to make sure that their border isn't visible.

Let's say the UIImageView would be called

UIImageView *photoImageView;

And the overlay with translucent and semi-translucent areas would be

UIImageView *imageOverlayView;

The way I see it, you need 3 different images for that imageOverlayView, depending on the device it's running on - 1 for iPad, 1 for iPhone 5 and 1 for other iPhones. Width of that image should be equal to (screen width - circle radius) * 2, height should

CGFloat circleRadius; //this would be the radius of translucent circle

So if you set the frame of the overlay properly:

CGRect imageFrame = photoImageView.frame;
imageOverlayView.frame = CGRectMake(circleRadius - imageFrame.size.width/2, circleRadius - imageFrame.size.height/2, (imageFrame.size.width - circleRadius)*2, (imageFrame.size.height - circleRadius)*2); //origin is set to the middle of the image.

you'd never see the edge of the grey area. MZimmerman6's answer for implementation of the movement is good, but you should also make sure you block the circle from getting out of the borders of underlying image.

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint new = [touch locationInView:imageOverlayView];
    delX = new.x - prevPoint.x;
    delY = new.y - prevPoint.y;
    CGRect overFrame = imageOverlayView.frame;
    overFrame.origin.x += delX;
    if (overFrame.origin.x < -imageFrame.size.width) {
        overFrame.origin.x = -imageFrame.size.width;
    }
    else if (overFrame.origin.x > 0) {
        overFrame.origin.x = 0;
    }
    overFrame.origin.y += delY;
    if (overFrame.origin.y < -imageFrame.size.height) {
        overFrame.origin.y = -imageFrame.size.height;
    }
    else if (overFrame.origin.y > 0) {
        overFrame.origin.y = 0;
    }
    [overlayView setFrame:overFrame];
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint new = [touch locationInView:imageOverlayView];
    delX = new.x - prevPoint.x;
    delY = new.y - prevPoint.y;
    CGRect overFrame = imageOverlayView.frame;
    overFrame.origin.x += delX;
    if (overFrame.origin.x < -imageFrame.size.width) {
        overFrame.origin.x = -imageFrame.size.width;
    }
    else if (overFrame.origin.x > 0) {
        overFrame.origin.x = 0;
    }
    overFrame.origin.y += delY;
    if (overFrame.origin.y < -imageFrame.size.height) {
        overFrame.origin.y = -imageFrame.size.height;
    }
    else if (overFrame.origin.y > 0) {
        overFrame.origin.y = 0;
    }
    [overlayView setFrame:overFrame];
}

EDIT With your pan gesture recognizer, checking if you aren't going too far needs a little change to the handlePan: method.

-(void)handlePan:(UIPanGestureRecognizer *)gesture {
    CGPoint newCenter = [gesture locationInView:self.view];
    if (newCenter.x < 50) {
        newCenter.x = 50;
    }
    else if (newCenter.x > self.view.frame.size.width - 50) {
        newCenter.x = self.view.frame.size.width - 50;
    }
    if (newCenter.y < 50) {
        newCenter.y = 50;
    }
    else if (newCenter.y > self.view.frame.size.height - 50) {
        newCenter.y = self.view.frame.size.height - 50;
    }
    gesture.view.center = newCenter;
}

If that 50 points margin is equal to circle radius, this will make sure your circle able to touch the edges of the screen, but unable to go beyond them.

OTHER TIPS

I would first initialize some UIImageView with a png image in it that will easily handle this moving frame with a hole in the center. You can the add this to your screen. Once this is done, use the touchesBegan, touchesMoved and other touch commands to find whether a user is touching that box and from that determine how far the user has moved from the previous point. Use this difference to then add or subtract values from the images current frame origin or center, and voila you have a moving box.

EDIT

In View.h

CGPoint prevPoint;
float delX;
float delY;
UIView *overlayView;

In View.m

-(void) viewDidLoad {
    overlayView = [UIView alloc] initWithFrame:CGRectMake(100,100,100,100)];
    [overlayView setBackgroundColor:[UIColor clearColor]];
    [self.view addSubview:overlayView];
    UIImageView *circImage = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,overlayView.frame.width,overlayView.frame.height)];
    [circImage setImage:[UIImage imageNamed:@"SomeImage.png"]];
    [overlayView addSubview:circImage];
    [self.view setNeedsDisplay];
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    prevPoint = [touch locationInView:overlayView];
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint new = [touch locationInView:overlayView];
    delX = new.x - prevPoint.x;
    delY = new.y - prevPoint.y;
    CGRect overFrame = overlayView.frame;
    overFrame.x += delX;
    overFrame.y += delY;
    [overlayView setFrame:overFrame];
    [self.view setNeedsDisplay];
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint new = [touch locationInView:overlayView];
    delX = new.x - prevPoint.x;
    delY = new.y - prevPoint.y;
    CGRect overFrame = overlayView.frame;
    overFrame.x += delX;
    overFrame.y += delY;
    [overlayView setFrame:overFrame];
    [self.view setNeedsDisplay];
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top