1

Xcode 7.3, iOS 9.3.1

I want to use two custom overlay views for when the user is about to take a picture and after while editing the picture. To change the overlay I would like to know if there is a callback method from the UIImagePickerControllerDelegate that will let me know when the user starts editing the picture, or when the user has tapped the take picture button.

The only methods I know of are:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker

I have looked here: UIImagePickerController with cameraOverlayView focusses when button in overlay is tapped, How to know I tap "taking photo button" with UIImagePicker and iOS - Taking A Picture After Button Tap in UIImagePickerController CustomOverlayView.

Or perhaps there is a way to get the tap event from the standard button by adding an observer.

Please help! Thanks in advance.

Community
  • 1
  • 1
serge-k
  • 3,394
  • 2
  • 24
  • 55

3 Answers3

2

you could use the UINavigationControllerDelegate that you also have to implement when using UIImagePickerController. implementing the delegate method [...]didShowViewController[...] like this

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    NSLog(@"%@", [viewController class]);
}

produces the following output (using the simulator, choosing UIImagePickerControllerSourceTypePhotoLibrary as the sourceType and navigating like this: photo albums overview > specific album > editing specific photo):

2016-04-08 00:19:36.882 ImagePicker[44578:4705834] PUUIAlbumListViewController
2016-04-08 00:19:41.341 ImagePicker[44578:4705834] PUUIMomentsGridViewController
2016-04-08 00:19:47.929 ImagePicker[44578:4705834] PUUIImageViewController

hope that helps!

André Slotta
  • 13,774
  • 2
  • 22
  • 34
  • Thanks. but the `UIImagePickerController` is still presented during capturing the photo and also while editing, the `- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated` method gets called only once, the log result is `PLUICameraViewController` – serge-k Apr 07 '16 at 22:27
  • You pointed me in the right direction by reminding me of how the image picker was presented. – serge-k Apr 07 '16 at 23:57
2

UIImagePickerControllerDelegate is quite poor but you can handle it by adding an observer:

Swift 3:

NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "_UIImagePickerControllerUserDidCaptureItem"), object:nil, queue:nil, using: { note in
    //Do something
})

Objective-C:

[[NSNotificationCenter defaultCenter] addObserverForName:@"_UIImagePickerControllerUserDidCaptureItem" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
    //Do something
}];
1

Xcode 8.2.1, iOS10.2.1

Before implementing please read the solution for earlier version to understand the basics. Thanks! The problem was that some of the names for various subviews have changed from iOS 9.3.1 to iOS 10.2.1.

Here is the complete code (see below where to insert), that replaces "//Code goes here" below:

for (UIView *subviewImagePickerControllerView in self.imagePickerController.view.subviews)
{
    if ([subviewImagePickerControllerView.class.description isEqualToString:@"UINavigationTransitionView"])
    {
        for (UIView *subviewUINavigationTransitionView in subviewImagePickerControllerView.subviews)
        {
            if ([subviewUINavigationTransitionView.class.description isEqualToString:@"UIViewControllerWrapperView"])
            {
                for (UIView *subviewUIViewControllerWrapperView in subviewUINavigationTransitionView.subviews)
                {
                    if ([subviewUIViewControllerWrapperView.class.description isEqualToString:@"CAMCameraViewControllerContainerView"])
                    {
                        for (UIView *subviewCAMCameraViewControllerContainerView in subviewUIViewControllerWrapperView.subviews)
                        {
                            if ([subviewCAMCameraViewControllerContainerView.class.description isEqualToString:@"CAMViewfinderView"])
                            {
                                for (UIView *subviewCAMViewfinderView in subviewCAMCameraViewControllerContainerView.subviews)
                                {
                                    if ([subviewCAMViewfinderView.class.description isEqualToString:@"CAMBottomBar"])
                                    {
                                        for (UIView *subviewCAMBottomBar in subviewCAMViewfinderView.subviews)
                                        {
                                            if ([subviewCAMBottomBar.class.description isEqualToString:@"CUShutterButton"] && [subviewCAMBottomBar.class isSubclassOfClass:[UIButton class]])
                                            {
                                                UIButton *shutterButton = (UIButton *)subviewCAMBottomBar;

                                                [shutterButton addTarget:self action:@selector(touchUpInsideCMKShutterButton) forControlEvents:UIControlEventTouchUpInside];
                                            }
                                            else
                                            {
                                                nil;
                                            }
                                        }
                                    }
                                }

                            }
                            else if ([subviewCAMCameraViewControllerContainerView.class.description isEqualToString:@"PLCropOverlay"])
                            {
                                for (UIView *subviewPLCropOverlay in subviewCAMCameraViewControllerContainerView.subviews)
                                {
                                    if ([subviewPLCropOverlay.class.description isEqualToString:@"PLCropOverlayBottomBar"])
                                    {
                                        for (UIView *subviewPLCropOverlayBottomBar in subviewPLCropOverlay.subviews)
                                        {
                                            if ([subviewPLCropOverlayBottomBar.class.description isEqualToString:@"PLCropOverlayPreviewBottomBar"])
                                            {
                                                for (UIView *itemPLCropOverlayPreviewBottomBar in subviewPLCropOverlayBottomBar.subviews)
                                                {
                                                    if ([itemPLCropOverlayPreviewBottomBar.class isSubclassOfClass:[UIButton class]])
                                                    {
                                                        UIButton *buttonPLCropOverlay = (UIButton *)itemPLCropOverlayPreviewBottomBar;

                                                        if ([buttonPLCropOverlay.titleLabel.text isEqualToString:@"Retake"])
                                                        {
                                                            UIButton *retakeButton = buttonPLCropOverlay;

                                                            [retakeButton addTarget:self action:@selector(touchUpInsideButtonRetake) forControlEvents:UIControlEventTouchUpInside];
                                                        }
                                                        else
                                                        {
                                                            nil;
                                                        }
                                                    }
                                                    else
                                                    {
                                                        nil;
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                nil;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        nil;
                                    }
                                }
                            }
                            else
                            {
                                nil;
                            }
                        }
                    }
                    else
                    {
                        nil;
                    }
                }
            }
            else
            {
                nil;
            }
        }
    }
    else
    {
        nil;
    }
}

Xcode 7.3, iOS9.3.1

I had to get this working, so I spent a lot of time figuring this out.

The gist of it is, I drill down the view hierarchy after the UIImagePickerController was presented, looking for CMKShutterButton and the retake button with a title of "Retake", then I attach a selector to the buttons' action, like so...

[shutterButton addTarget:self action:@selector(touchUpInsideCMKShutterButton) forControlEvents:UIControlEventTouchUpInside];

[retakeButton addTarget:self action:@selector(touchUpInsideButtonRetake) forControlEvents:UIControlEventTouchUpInside];

Drop the code below into the completion block that is called after your image picker is presented:

[self presentViewController:self.imagePickerController animated:true completion:^(void){

     //Code goes here

}

Here is the complete code, that replaces "//Code goes here" above:

for (UIView *subviewImagePickerControllerView in self.imagePickerController.view.subviews)
{
    if ([subviewImagePickerControllerView.class.description isEqualToString:@"UINavigationTransitionView"])
    {
        for (UIView *subviewUINavigationTransitionView in subviewImagePickerControllerView.subviews)
        {
            if ([subviewUINavigationTransitionView.class.description isEqualToString:@"UIViewControllerWrapperView"])
            {
                for (UIView *subviewUIViewControllerWrapperView in subviewUINavigationTransitionView.subviews)
                {
                    if ([subviewUIViewControllerWrapperView.class.description isEqualToString:@"PLImagePickerCameraView"])
                    {
                        for (UIView *subviewPLImagePickerCameraView in subviewUIViewControllerWrapperView.subviews)
                        {
                            if ([subviewPLImagePickerCameraView.class.description isEqualToString:@"CMKBottomBar"])
                            {
                                for (UIView *itemCMKBottomBar in subviewPLImagePickerCameraView.subviews)
                                {
                                    if ([itemCMKBottomBar.class.description isEqualToString:@"CMKShutterButton"] && [itemCMKBottomBar.class isSubclassOfClass:[UIButton class]])
                                    {
                                        UIButton *shutterButton = (UIButton *)itemCMKBottomBar;

                                        [shutterButton addTarget:self action:@selector(touchUpInsideCMKShutterButton) forControlEvents:UIControlEventTouchUpInside];
                                    }
                                    else
                                    {
                                        nil;
                                    }
                                }
                            }
                            else if ([subviewPLImagePickerCameraView.class.description isEqualToString:@"PLCropOverlay"])
                            {
                                for (UIView *subviewPLCropOverlay in subviewPLImagePickerCameraView.subviews)
                                {
                                    if ([subviewPLCropOverlay.class.description isEqualToString:@"PLCropOverlayBottomBar"])
                                    {
                                        for (UIView *subviewPLCropOverlayBottomBar in subviewPLCropOverlay.subviews)
                                        {
                                            if ([subviewPLCropOverlayBottomBar.class.description isEqualToString:@"PLCropOverlayPreviewBottomBar"])
                                            {
                                                for (UIView *itemPLCropOverlayPreviewBottomBar in subviewPLCropOverlayBottomBar.subviews)
                                                {
                                                    if ([itemPLCropOverlayPreviewBottomBar.class isSubclassOfClass:[UIButton class]])
                                                    {
                                                        UIButton *buttonPLCropOverlay = (UIButton *)itemPLCropOverlayPreviewBottomBar;

                                                        if ([buttonPLCropOverlay.titleLabel.text isEqualToString:@"Retake"])
                                                        {
                                                            UIButton *retakeButton = buttonPLCropOverlay;

                                                            [retakeButton addTarget:self action:@selector(touchUpInsideButtonRetake) forControlEvents:UIControlEventTouchUpInside];
                                                        }
                                                        else
                                                        {
                                                            nil;
                                                        }
                                                    }
                                                    else
                                                    {
                                                        nil;
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                nil;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        nil;
                                    }
                                }
                            }
                            else
                            {
                                nil;
                            }
                        }
                    }
                    else
                    {
                        nil;
                    }
                }
            }
            else
            {
                nil;
            }
        }
    }
    else
    {
        nil;
    }
} 

And here is the method I am attaching, which goes in the view controller that is presenting the image picker controller:

- (void)touchUpInsideCMKShutterButton
{
    NSLog(@"Take");
}

- (void)touchUpInsideButtonRetake
{
    NSLog(@"Re-take");
}

Hope this helps someone! Thanks.

serge-k
  • 3,394
  • 2
  • 24
  • 55
  • Hii, @serge-k i had tried your code, its working Fine in iOS 9.3 but its not working in iOS 10.2.1 device. – MAhipal Singh Feb 22 '17 at 07:46
  • @MahipalSingh thanks for trying out this solution. I have a few deadlines to meet this week, but I will be able to take a look at this code over the weekend. I'll post an updated version after investigate further. – serge-k Feb 23 '17 at 05:42
  • @MahipalSingh Try the newly posted solution. It worked on my iPhone 5s that has 10.2.1, and don't try it on simulator, since it has no camera :P – serge-k Feb 27 '17 at 01:10
  • @MahipalSingh you are quite welcome! It would be great to revise this solution to not use actual "names" for the various views; there must be a better way. – serge-k Feb 27 '17 at 18:19
  • In Swift, please! – Roman Dec 21 '20 at 09:55