UIImagePickerController cameraOverlay behind shutter - ios

Can not find any definitive answer, but it looks like it is not possible. I am just displaying a frame image as an overlay to guide the user where the photo should be positioned. However the frame appears on top of the shutter on the opening and closing animation. Is there any (app store compliant) way to make the overlay view appear behind the shutter animation?
Also, when to remove/hide the overlay after the user pressed the take photo button? I have allowsEditing enabled, so I don't want the frame overlay being shown when editing the image. I can not figure how to capture that event.
Thanks

On the iPad this problem doesn't exist, and the overlay view is behind the shutter animation by default. But on the iPhone, the overlay appears at front.
EDIT:
I've found a solution that worked for me.
You have to set your overlay view as a subview in this method:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if (!viewController)
return;
UIView* controllerViewHolder = viewController.view;
UIView* controllerCameraView = [[controllerViewHolder subviews] objectAtIndex:0];
UIView* controllerPreview = [[controllerCameraView subviews] objectAtIndex:0];
[controllerCameraView insertSubview:self.overlayView aboveSubview:controllerPreview];
}
Hope it helps
Original source:
http://www.alexcurylo.com/blog/2009/06/18/uiimagepickercontroller-in-3-0/

Related

Covering window of UIAppDelegate with an overlay make user can't touch on extensions of UIActivityViewController when it's displayed

I'm creating an overlay which will cover all displaying views on screen. This overlay always appears even in case rootViewController changes, pushing or presenting.
My idea is
Create CustomWindow which is a subclass of UIWindow. After that replacing default window of UIApplication with CustomWindow, create a new rootViewController for my new window.
In CustomWindow, I have an overlay (is an UIView). Overlay have light gray color with an alpha and every event on overlay will be pass through to below view.
Whenever CustomWindow add a new subview, i will bring overlay to front. It's make sure overlay will be on the top in every case.
CustomWindow
#implementation CustomWindow
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_overlay = [[UIView alloc] initWithFrame:self.bounds];
_overlay.userInteractionEnabled = NO;
_overlay.backgroundColor = [UIColor lightGrayColor];
_overlay.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:_overlay];
}
return self;
}
- (void)didAddSubview:(UIView *)subview {
[super didAddSubview:subview];
[self bringSubviewToFront:_overlay];
}
#end
Everything works fine in every case even when pushing, presenting or changing rootViewController.
Problem
But when i show an UIActivityViewController, I can't click on any extensions which are displayed on UIActivityViewController.
Magically
When i click outside of UIActivityViewController or click on Cancel Button, UIActivityViewController is dismissed normally.
If i change color of overlay to clearColor, it works fine too.
My question is
How can i touch on extensions when i have overlay on window and overlay have a color ?
If i can't, can anyone tell me why it happens ? It's perfect when you can quote the reason from a document.
I'm pretty sure this doesn't relate to how i initialize UIActivityViewController or the way i show UIActivityViewController.
MORE
I found a problem quite similar to this problem on Android. But i'm not sure because i haven't seen any official document about it from Apple. One more thing is when changing color to clearColor can affect touch. So actually, i don't think they are same.
This is due to a UIRemoveView (private) in the hierarchy. As best I can determine, your app cannot forward events directly to remote views. I suspect this is a security measure to prevent you from presenting the share dialog and automatically sending a touch event to it to do an external action the user didn't request. Remote views don't run in your application's process. The "Copy" button is interacted with across an XPC link.
This all means that if the remote view is covered by one of your views, there's no way (at least that I've found) to interact with it. You have to ensure that you're not covering it.
Actually doing that is simple. The thing that holds the remote view is called a UITransitionView and is used for other OS-level things that you probably shouldn't be covering either. So don't:
- (void)didAddSubview:(UIView *)subview {
[super didAddSubview:subview];
if ([subview isKindOfClass:NSClassFromString(#"UITransitionView")]) {
// To raise it above your overlay;
// otherwise it's immediately above the view controller (below the overlay)
[self bringSubviewToFront:subview];
} else {
[self bringSubviewToFront:self.overlay];
}
}
But.... This requires you to talk about UITransitionView in your code. This is both fragile, and possibly a forbidden use of private APIs.
Otherwise you'll have to wrap your UIActivityViewController requests with some call/notification that tells the window not to cover views until we're done (which you'll have to clear in the completion handler).

Picker View Background Color during Rotation

I am having an issue with my picker view rotating. I am using a normal UIPickerView and autorotation, all of which is done in code (but the autorotation isn't what I'm concerned about). The picker view does exactly what I want it to do after rotation. The issue is that my background is black, and during rotation the background of the picker view turns white in places. I am pretty sure that these are the deep subviews of the picker view simply because of debugging using Xcode's visual debugger and taking mid-rotation screen shots.
My question is, how do I get the background of the picker view to not appear momentarily white?
I have tried something along these lines:
-(void)setBackgroundBlackForSubviews:(NSArray *)subviews
{
if (subviews.count) {
for (UIView *view in subviews) {
[view setBackgroundColor:[UIColor blackColor]];
[self setBackgroundBlackForSubviews:view.subviews];
}
}
}
and pass in pickerView.subviews as the initial parameter, but this doesn't produce the desired result.
So, what solution should I try to get the background to appear black throughout the entire rotation process?

Force UINavigationBar to overlay container below instead of pushing it down

I was just wondering if there is a simple way to specify whether a UINavigationBar should overlay its content when shown. I currently have a UINavigationController that contains a custom UIViewController with a UIScrollView, which contains a UIPageViewController (I wanted a zooming/scrollable UIPageViewController).
When I call:
[self setNavigationBarHidden:NO animated:YES];
From within my UINavigationController, the UINavigationBar animates in, but pushes the custom container with all its content down, instead of overlaying it.
The bar is set to translucent and I've tried all the settings I can think of. I changed the extendEdges settings in the child view controllers and that resized the content when the navigation bar came in, instead of pushing it down. But I still can't work out how to get it to overlay instead.
Many thanks.
Ok, apologies. This just reveals how little I know about iOS programming...
I noticed that the container's view origin y value was -44. So adding the following within my container class:
- (void) viewDidLayoutSubviews
{
CGRect boundsRect = self.view.bounds;
boundsRect.origin = CGPointMake(0, 0);
self.view.bounds = boundsRect;
}
Results in the view staying at the top of the screen, so the UINavigationBar overlays it nicely when it appears.
EDIT: Actually the proper way appears to be just calling:
self.automaticallyAdjustsScrollViewInsets = NO;

Orientation without animation giving weird result when UIAlertView is present

I am facing a weird problem here.
For some reason I am disabling the animation during orientation change in my view controller using [UIView setAnimationsEnabled:NO];
But when the alert view is present and if I change the orientation then it is giving weird result.
The attached screen shot is when I change the orientation to landscape.
Please note: I am using standard UIAlertView and it is default overlay which is shown when the alert view is present and there is no customisation involved here.
As per the documentation
If you disable animations, code inside subsequent animation blocks is still executed but no animations actually occur. Thus, any changes you make inside an animation block are reflected immediately instead of being animated.
So it should not affect the resizing of the default overlay. Is it a restriction in disabling animation !??
I am not understanding why I am getting like this.
Could anyone please help in solving this.
When you set [UIView setAnimationsEnabled:NO];, UIAlertView is not resizing it's Overlay View (I think it's a bug).
Optionally you can restrict orientation when alert view is on screen as following.
Create a BOOL variable in .h file.
BOOL shouldRotate;
initialize it with YES in viewDidload.
And whenever you show alert at that time make shouldRotate = NO;
And implement UIAlertView delegate as follows:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
shouldRotate = YES;
}
Hope will help you.
Edit: As you want both no animation and rotation with alert view
This is actually a hack but works,
alert is an UIAlertView's object declared in .h file.
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
if (UIInterfaceOrientationPortrait == UIInterfaceOrientationIsPortrait(fromInterfaceOrientation)) {
UIImageView *imgView = (UIImageView *)[alert.superview.subviews objectAtIndex:0];
imgView.frame = CGRectMake(0.0, 0.0, 480.0, 320.0);
}
else{
UIImageView *imgView = (UIImageView *)[alert.superview.subviews objectAtIndex:0];
imgView.frame = CGRectMake(0.0, 0.0, 320.0, 480.0);
}
}
Another possibility to cope with this bug would be to dismiss the alert view programmatically before rotation and displaying a new one after rotation completed.
That would automatically work for any iOS device independent of screen size.
This seems to be a bug in iOS6 and below and is fixed in iOS7.

cameraOverlayView prevents editing with allowsEditing

Editing a photo after it's been taken (moving and scaling it) works fine in my app with this line:
[imagePicker setAllowsEditing:YES];
But if I also use a cameraOverlayView, the editing mode doesn't work anymore. The screen comes up, but pan and pinch gestures don't make anything happen.
I'm using your average image picker controller:
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
And I add a camera overlay view, created from a custom view controller's view:
CameraOverlayViewController *overlayController = [[CameraOverlayViewController alloc] init];
UIView *overlayView = overlayController.view;
[imagePicker setCameraOverlayView:overlayView];
In IB, that view is set up to enable user interaction and multiple touch, which allows it to zoom and focus while taking the picture. But once the picture is taken and it enters editing mode, you cannot pan or pinch to move or scale the photo.
What am I missing?
Does your overlay take up the entire space of the camera view? If so, touches are going to the overlay instead of the view below, even if you have a transparent background.
Add this method to your overlay view and it will ignore touches so that they are passed to the views below. (You are overriding a method of UIView that detects touches.)
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
return NO;
}
Note: as well as that fantastic tip, you may also want to use this piece of info, to remove your overlay view, at that stage: UIImagePicker cameraOverlayView appears on Retake screen

Resources