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.
Related
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).
I’m trying to make an iOS Action app extension with minimal UI. Basically it would just show a progress indicator until the action completed. I just want to be able to animate the view so that it slides down from the top & then slides back up when the action has completed. If anyone is familiar with Instapaper’s Share extension, then that’s the kind of basic UI I’m looking for.
The problem is that when I try to duplicate this functionality - I just have a small UIView that animates down from the top - I get a black background behind my view. I can’t figure out how to make that background transparent so that the stuff behind my view is still visible. Does anyone know how to do this?
As a starting point I’m just using the default Action Extension template that’s created by Xcode...
Create a new iOS app project in Xcode.
Add a new target -> Action Extension.
In the ActionViewController.m file add a viewWillAppear method to animate the view (using a 1 second animation so that the black background is easily seen):
Code:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
CGRect currFrame = self.view.frame;
CGRect newFrame = currFrame;
newFrame.origin.y -= newFrame.size.height;
self.view.frame = newFrame;
[UIView animateWithDuration:1.0 animations:^{
self.view.frame = currFrame;
}];
}
When this is run the view is animated sliding down from the top. However rather than seeing the UI of the calling App all you see is a black background.
I’ve tried a number of things - changing the modalPresentationStyle (doesn’t seem to do anything), setting the entire view to hidden (this just makes the whole screen black), etc.
For reference this is using iOS 9.3.2 and Xcode 7.3.1.
From what I understand from Apple docs
In iOS, an Action extension:
Helps users view the current document in a different way
Always appears in an action sheet or full-screen modal view
Receives selected content only if explicitly provided by the host app
The fact that the Action extension always appear in a full-screen view on an iPhone might mean that there's no way of having a transparent background.
I am certain that a Share extension can be animated (I've done it myself) how you want it and have a transparent background. That's why Instapaper's Share extension works nicely.
You are facing two problems:
1. When you present a view controller, the default behavior is the controller is full screen context. That is the reason you see a black screen.
2. You are trying to change self.view.frame when the controller is presented on full screen.
Yet there is a way to achieve this kind of behavior you are looking for, in one of three ways:
A. Specify "modalPresentationStyle" to "UIModalPresentationOverCurrentContext" and set the presenting controller to "definesPresentationContext".
That way, when you present the controller, the presenting controller will be behind the presented controller.
And insted of changing self.view.frame you will set self.view background color to clear, and add a subview and use it as a background view:
//Presenting view controller:
-(void) presentPopUpViewController {
self.definesPresentationContext = YES; //self is presenting view controller
self.presentedVC.modalPresentationStyle = UIModalPresentationOverCurrentContext;
[self presentViewController:self.presentedVC animated:NO completion:nil];
}
//Presented view controller:
-(void) viewDidLoad {
[super viewDidLoad];
CGRect currFrame = self.view.frame;
CGRect newFrame = currFrame;
newFrame.origin.y -= newFrame.size.height;
self.myBackroundView = [[UIView alloc] init];
self.myBackroundView.backgroundColor = [UIColor yellowColor];
self.myBackroundView.frame = newFrame;
[self.view addSubview:self.myBackroundView];
self.view.backgroundColor = [UIColor clearColor];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[UIView animateWithDuration:5.0 animations:^{
self.myBackroundView.frame = self.view.frame;
}];
}
B. Add the presented view controller as a Child view controller. that way the life cycle stays the same, but you can add I'ts view as a subview, and change I'ts frame.
//Presenting view controller:
-(void) presentChildViewController {
[self addChildViewController:self.presentedVC];
[self.view addSubview:self.presentedVC.view];
[self.presentedVC didMoveToParentViewController:self];
}
//Presented view controller:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
CGRect currFrame = self.view.frame;
CGRect newFrame = currFrame;
newFrame.origin.y -= newFrame.size.height;
self.view.frame = newFrame;
[UIView animateWithDuration:1.0 animations:^{
self.view.frame = currFrame;
}];
}
C. Don't use UIViewController, use UIView. Use a "Decorator" object, that you pass it the ViewController you would like the view to disaply on, and the "Decorator" will add the view as subview, and deal with the animation. No need for an example for this scenario.
It is wrong to start animations when your view hasn't yet appeared. Can you, please, try the same code in viewDidAppear.
Also animating main view controller's view will make underlying layers visible, so you've got to use another view on top of view controller's main view, like this:
UIView *progressView = [[UIView alloc] init];
progressView.frame = self.view.bounds;
progressView.backgroundColor = [UIColor redColor];
[self.view addSubView:progressView];
I have a problem with [UIView animationWithDuration] when trying to animate a button when the keyboard come up. I have a notification tell me when the keyboard comes up then I have the ViewController call this method in the view. The button animates but not correctly. It just animates from a random position on the screen to the position it was at previously. The reason I bring this up again is because I've seen answers from other posts saying that setting the view's translatesAutoresizingMaskIntoConstraints property to YES in the ViewController will fix the problem, but it doesn't fix the problem.
[self.view setTranslatesAutoresizingMaskIntoConstraints:YES];
The animation is below:
- (void)animateForKeyboardAppearanceWithKeyboardSize:(CGSize)keyboardSize; {
[UIView animateWithDuration:0.3f
animations:^{
[self.sendSMSButton setFrame:CGRectMake(0,
self.frame.size.height - keyboardSize.height - self.sendSMSButton.frame.size.height,
self.frame.size.width,
self.sendSMSButton.frame.size.height)];
}];
}
Anyone know what's happening? Thanks in advance.
Have you ensured that this method isn't being called repeatedly? Also try subclassing the button, override -setFrame and double check to see if something else is setting the frame of your button while you are trying to animate it.
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/
I have a UISegmentedControl set up in my XIB. I want it to appear on viewDidLoad and if the user taps the area of the screen it's in, and then to disappear if the user taps it again or to fade out if the user leaves it alone.
In looking around for how to manage this I've found a lot of stuff about fading UIViews, but not as much on fading individual subviews, and little at all on fading elements in the XIB. I tried to adapt the UIView stuff but failed.
How can I make this work?
EDIT: Okay, I've got the appearance at viewDidLoad and the fade out working. But when the user taps the area where the UISegmentedControl is (now invisible because alpha=0), nothing happens. This is the code I'm using:
- (IBAction)tapInvisibleSegContr
//This is connected to the UISegmentedControl with the action Touch Up Inside. Until now, the segmented control has been at alpha=0 since fading after viewDidLoad.
{
self.segContrAsOutlet.alpha=1.0;
[self fadeMethodThatWorksInViewDidLoad];
NSLog(#"Yup, tapped.");
}
I'm not even getting the NSLog. I've got the action hooked up to the UISegmentedControl, with the action Touch Up Inside. What am I missing?
If it is resident in a xib, just put his alpha to 0, do the properly connections: an Outlet and an IBAction for value changed
Then in the viwDidLoad right after [super viewDidLoad] write:
[UIView animateWithDuration:1 animations:^{self.mySegOutlet.alpha = 1;}];
Inside the IBAction right after you code the answer before the last } write:
[UIView animateWithDuration:1 animations:^{self.mySegOutlet.alpha = 0;}];
This is the easiest method.
Bye
In the xib set your control's alpha to 0.0, then use UIView animation methods to animate its alpha to 1.0. For example:
[UIView animateWithDuration:1.0 animations:^{
self.segmentedControl.alpha = 1.0f;
}];
EDIT: To your problem with not getting the action called, try attaching it for the value changed control event - I don't think UISegmentedControl sends for touch up inside.