0

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?

StuartM
  • 6,743
  • 18
  • 84
  • 160
  • It doesn't really need to be that huge - just giving a margin frame.size.width on right and left side of the circle and frame.size.height on top and bottom would be enough to make sure that user won't see borders of the gray area – johnyu Jul 23 '13 at 15:19
  • The above example is two UIImageViews. One on the bottom holds the photo and the second is the grey area and the circle all in one. How would a margin increase the width only of the grey area? – StuartM Jul 23 '13 at 15:38
  • I mean moving together the translucent and semi-translucent area so that from the right edge of the circle to the right edge of the semi-translucent area the distance is equal to frame.size.width of the UIImageView below. Actually, it could be less than that, depending on how far you want the circle to move. If it must stay within borders of the imageView, then imageView.frame.size.width - (circleRadius * 2) should be enough on the right and left side. (Analogically, with height, on top and bottom) – johnyu Jul 23 '13 at 15:55
  • I'm sorry I don't think I understand, could submit a code example as an answer please? – StuartM Jul 23 '13 at 16:35
  • See if this helps for your overlay view - http://stackoverflow.com/questions/11792563/can-a-particular-rect-of-uiview-have-different-alpha/14645130#14645130 – Gopal R Jul 24 '13 at 14:20

2 Answers2

1

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];
}
MZimmerman6
  • 8,445
  • 10
  • 40
  • 70
  • How would I then deal with different screen sizes? Produce an image for iphone5 and one for smaller? – StuartM Jul 15 '13 at 21:29
  • @MZimmernan6 - also I have the issue that it is moveable. Therefore if i used an image I would need to make an over sized image that would take into account how much it would be moved... Surely this is not the best option? – StuartM Jul 15 '13 at 21:49
  • it being movable is not an issue. An you do not have to worry about making an "over-sized" image to be able to move the image, just simply change the origin of the image, and you should be fine. As for iPhone 5, you may want to make the image larger, or you may not want to, that is completely up to you – MZimmerman6 Jul 16 '13 at 12:54
  • What do you mean change the origin of the image. If I have an image which is the size of portrait iphone5 with a Circle in the middle which is transparent. Then when the image is moved the sides of the image would be seen, therefore not always covering the photo in the image view below which is what I am after. – StuartM Jul 16 '13 at 16:55
  • when you add a view programmatically to a view you do something like `[[UIView alloc] initWithFrame:CGRectMake(OriginX, OriginY, Width, Height)]` by origin I mean the top left corner of a UIView. You can use the information you get from `touchesMoved` and `touchesBegan` to alter these `X` and `Y` values, to in turn move the view. – MZimmerman6 Jul 16 '13 at 18:04
  • I am going to add some code above to make it a bit more clear. – MZimmerman6 Jul 16 '13 at 18:06
  • Thanks, however I am not sure we understand each other let me update the question with some more information... – StuartM Jul 18 '13 at 16:49
1

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.

johnyu
  • 2,152
  • 1
  • 15
  • 33
  • Thanks this is great. I have updated my question with a further edit to explain what I have completed so far. Ideally I need to know how to implement these touch checks within my gesture recognizer handlePan method. I move the UIImageView from the center point around on the screen, so how would I do these checks that the center is not outside of a margin set around the screen (as such)?? – StuartM Jul 24 '13 at 20:11
  • That is the best!!!!!! :) So simple, but had no idea where to start! If you can add any information of where to find that sort of information out for the future that would be great too. Thanks again – StuartM Jul 25 '13 at 10:36
  • I just made the calculations myself. :) – johnyu Jul 25 '13 at 10:41
  • @johnyu can you please explain (code) how can i crop the image under the circle in a new image ? Thanks a lot – vishal dharankar Nov 23 '13 at 14:08
  • To be honest, I have no idea. But the solution should be somewhere on SO, since I remember seeing explanations how to do a screenshot of part of the screen a few times. – johnyu Nov 25 '13 at 14:26