Chris Dunn
Chris Dunn

Reputation: 33

UIImagePickerController Overlay Buttons Not Firing

I have a UIImagePickerController of type camera when the user lands on a page. I have put a custom camera overlay on top of the UIImagePickerController, but none of the button events are firing. I know most of this code is from a base Apple code, so I am perplexed as to what is happening.

@interface TakePhotoViewController : UIImagePickerController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
...

- (void)showImagePickerForSourceType:(UIImagePickerControllerSourceType)sourceType
{
if (self.capturedImages.count > 0)
{
    [self.capturedImages removeAllObjects];
}

self.sourceType = sourceType;
self.delegate = self;

if (sourceType == UIImagePickerControllerSourceTypeCamera)
{
    /*
     The user wants to use the camera interface. Set up our custom overlay view for the camera.
     */
    self.showsCameraControls = NO;

    /*
     Load the overlay view from the OverlayView nib file. Self is the File's Owner for the nib file, so the overlayView outlet is set to the main view in the nib. Pass that view to the image picker controller to use as its overlay view, and set self's reference to the view to nil.
     */
    [[NSBundle mainBundle] loadNibNamed:@"CameraOverlay" owner:self options:nil];
    float scale = [self getScaleForFullScreen];
    self.cameraViewTransform = CGAffineTransformMakeScale(scale, scale);
    self.overlayView.frame = self.cameraOverlayView.frame;
    self.cameraOverlayView = self.overlayView;
    self.overlayView = nil;
}

}

The CameraOverlay's owner is TakePhotoViewController. One of the buttons inside of the CameraOverlay sends a Touch Up Inside event to the outlet function listed below. The code in the TakePhotoViewController attached to a button is below, of which no logs are firing:

- (IBAction)outlet:(id)sender {
NSLog(@"outlet");
}

Upvotes: 3

Views: 1915

Answers (2)

Smartcat
Smartcat

Reputation: 2882

I ran across another way this can happen, at least if you're not subclassing UIImagePickerController (Apple says not to subclass it).

I created a "helper" class that creates, configures and presents the UIImagePickerController in a show() method of the helper class. When I created the helper class, I did so simply inside a method, thinking that UIImagePickerController would be displayed modally and synchronously.

So after presenting the UIImagePickerController, which indeed appeared, my helper class was then destroyed resulting in no button handlers that could be called from my custom overlay within the UIImagePickerController.

So for my fix, I simply had to construct my helper class as a member property of the class that wants to call the helper's show().

Upvotes: 0

matt
matt

Reputation: 534966

The problem is this line:

self.overlayView.frame = self.cameraOverlayView.frame;

Our cameraOverlayView is nil; it has no frame, because it doesn't even exist yet. So we are giving the overlayView a zero frame. It is dimensionless. The button appears, but it has a zero-sized superview and therefore cannot be tapped.

Now, you may ask, why is that? It's because of the way touch delivery works in iOS. To be touchable, a subview's superview must also be touchable, because the superview is hit-tested for the touch before the subview. But a zero-size view is not touchable: your touch misses the overlayView, so it misses the button as well.

The solution might be as simple as giving the overlayView a reasonable real frame. There may also be timing problems about when you do that (e.g. it may be that you cannot really set the frame until the image picker is about to appear - viewWillAppear:), but in any case this is the place to start.

Upvotes: 5

Related Questions