Gold Challenge: crosshairs and editing


#1

So I got the crosshairs to display. I created a custom UIView and added it using the cameraOverlayView property. Works great, except when the camera goes into edit view afterwards, the crosshairs are still there in the edited image, and panning and zooming don’t work any more. However, when I save the image, the overlay is no longer there. Any clue as to what’s going on?

Here’s the code for Crosshairs.m.

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        [self setCrossHairColor:[UIColor colorWithRed:8 green:8 blue:8 alpha:.7]];
        [self setBackgroundColor:[UIColor clearColor]];
    }
    return self;
}


- (void)drawRect:(CGRect)rect
{
    // Drawing code
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGRect bounds = [self bounds];
    
    // Figure out the center of the bounds rectangle
    CGPoint center;
    center.x = bounds.origin.x + bounds.size.width / 2.0;
    center.y = (bounds.origin.y + bounds.size.height / 2.0) - 20; // 20 up because of toolbar at bottom.
    
    // The width of the crosshairs should be 2px
    CGContextSetLineWidth(ctx, 2);
    
    // Start and end points for vertical line
    CGPoint topVert;
    topVert.x = center.x;
    topVert.y = center.y - 40;
    
    CGPoint botVert;
    botVert.x = center.x;
    botVert.y = center.y + 40;
    
    // Start and end points for horizontal line
    CGPoint topHori;
    topHori.y = center.y;
    topHori.x = center.x - 40;
    
    CGPoint botHori;
    botHori.y = center.y;
    botHori.x = center.x + 40;
    
    // Stroke color and bg
    [[self crossHairColor] setStroke];
    
    // Draw vertical line
    CGContextMoveToPoint(ctx, topVert.x, topVert.y);
    CGContextAddLineToPoint(ctx, botVert.x, botVert.y);
    CGContextStrokePath(ctx);
    
    // Draw horizontal line
    CGContextMoveToPoint(ctx, topHori.x, topHori.y);
    CGContextAddLineToPoint(ctx, botHori.x, botHori.y);
    CGContextStrokePath(ctx);
}

And here’s the takePicture method from DetailViewController.

- (IBAction)takePicture:(id)sender 
{
    UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
    // If our device has a camera, take a picture. Otherwise, pick from library
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
        [imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera];
        Crosshairs *reticle = [[Crosshairs alloc] initWithFrame:CGRectMake(imagePicker.view.frame.origin.x,
                                                                           imagePicker.view.frame.origin.y, imagePicker.view.frame.size.width, imagePicker.view.frame.size.height-self.tabBarController.tabBar.frame.size.height)];
        [imagePicker setCameraOverlayView:reticle];
    } else {
        [imagePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
    }
    [imagePicker setDelegate:self];
    [imagePicker setAllowsEditing:YES];
    [self presentViewController:imagePicker animated:YES completion:nil];
}

I’ll keep working at this, but any insight is appreciated as to what’s wrong. (Not that I don’t feel like I’ve technically solved the Gold challenge, but this kind of behavior is unexpected and semi-broken…)

UPDATE: From what I can tell, I think the overlay view sticks around when you get to the editing view, and it being on top prevents you from tapping on anything below, which is why you can’t resize the image. There doesn’t seem to be any method that I can find from which I can dismiss the overlay once in editing mode, though, and I can’t figure out what the subviews of UIImagePickerController are called…


#2

I haven’t found a way to dismiss the overlay once in editing mode, however I found you can add this method to the reticle view to ignore touches to its view and pass through to the view below it (allowing camera buttons/editing to work)

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { return NO; }

That method is part of UIView and you are overriding it to always return NO so that it doesn’t capture the touches, I believe.


#3

I also got the same question in dismissing the overlay in editing. I can just enable editing by reducing the frame size of the crosshair such that the image underneath can be ‘touched’.

But I do believe there is a smart way to dismiss the overlay, would Joe help on this? :smiley:


#4

[quote=“tomauhk”]I also got the same question in dismissing the overlay in editing. I can just enable editing by reducing the frame size of the crosshair such that the image underneath can be ‘touched’.

But I do believe there is a smart way to dismiss the overlay, would Joe help on this? :smiley:[/quote]

I did the same thing as tomauhk by reducing the crosshair view. So I have the same question as tomauhk :smiley:


#5

[quote=“billyshih”]I haven’t found a way to dismiss the overlay once in editing mode, however I found you can add this method to the reticle view to ignore touches to its view and pass through to the view below it (allowing camera buttons/editing to work)

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { return NO; }

That method is part of UIView and you are overriding it to always return NO so that it doesn’t capture the touches, I believe.[/quote]

Thanks for this one.


#6

DamirMarusic,

Thanks for the solution. Do you have a typo in your solution? In DetailViewController.m, you wrote:

Crosshairs *reticle = [[Crosshairs alloc] initWithFrame:CGRectMake(imagePicker.view.frame.origin.x,
                                                                           imagePicker.view.frame.origin.y, imagePicker.view.frame.size.width, imagePicker.view.frame.size.height-self.tabBarController.tabBar.frame.size.height)];

When an imagePicker is displayed, it doesn’t have a tabBar, it has a toolbar. I think self.tabBarController.tabBar.frame.size.height evaluates to 0 (effectively doing nothing). Thus, that is why you needed to again manually adjust the crosshair by 20 points in drawRect. You might try

CrossHairs *reticle = [[CrossHairs alloc] initWithFrame:CGRectMake(imagePicker.view.frame.origin.x, imagePicker.view.frame.origin.y, imagePicker.view.frame.size.width, imagePicker.view.frame.size.height - imagePicker.toolbar.frame.size.height)];

imagePicker.toolbar.frame.size.height evaluates to 44 points, as expected. Therefore, you don’t need to make the adjustment in drawRect