iOS - CATransition and transitionWithView issues - ios

Whenever I use either CATransition or transitionWithView to "push" one view from the right, there is a brief moment where the view that's getting pushed in fades in from black (or whatever the background color is), and the view that's getting pushed away fades out to black.
This might be the intended effect, but it looks messy on my app, and was wondering if anyone knows of a way to prevent this "fade out/in" effect?
Here is the CATransition code I am using to present the new view:
myView = [[MyView alloc] initWithNibName:#"MyView" bundle:nil];
[myView setDelegate:self];
[[mainView layer] addAnimation:pushRightTransition forKey:nil];
// Add the view:
[mainView addSubview:[myView view]];

Related

view loading from the bottom doesn't fill whole view

I am using this code to load a view when I touch a button in Xcode.
UIStoryboard *storyboard = self.storyboard;
UIViewController *svc = [storyboard instantiateViewControllerWithIdentifier:#"FirstCar"];[self presentViewController:svc animated:YES completion:nil];
The view loads from the bottom, which I wish it didn't but loaded from the side instead. The main problem is that when it finish loading there is a gap at the top of about 1/2 inch. I have used this code to load it above the top depending screen size.
backgroundView = [[UIImageView alloc] initWithFrame:CGRectMake(-20, -20, 454, 776)];
It used to work ok but now for some reason it doesn't. And when I top/hold on an object to move it using "DragView", the object moves jerkily but the whole view moves up and down. I can even make the views contents completely disappear by swiping down. It doesn't go the the previous view just totally blank black. I don't know if that is related but something is weird.
Does anyone have any ideas what I am doing wrong.
Thanks in advance.
What you are describing is the default behavior of a presented view controller in iOS 13 - presented VCs slide in from the bottom and leave a gap at the top (indicating that the user can dismiss by dragging down).
You can remove the gap (and swipedown behavior) by setting the presented VC's modalPresentationStyle to fullscreen like this:
svc.modalPresentationStyle = UIModalPresentationFullScreen;
Add that line before calling present (or you can set that value in your storyboard) and you should see it cover the screen. You can find documentation of other presentation styles in the Apple docs
As for the right-to-left animation you mentioned, a sideways slide in is usually associated with UINavigation controller pushes rather than modal presentations, but as mentioned in this post, you can achieve the sideways animation on a modal using a custom transition.
Here's the relevant code in that post:
CATransition *transition = [[CATransition alloc] init];
transition.duration = 0.5;
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
[transition setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[self.view.window.layer addAnimation:transition forKey:kCATransition];
[self presentViewController:svc animated:false completion:nil];

iOS7 slideout drawer draggable bug

I am trying to implement a slideout drawer similar to a the one found in this guide: http://www.raywenderlich.com/32054/how-to-create-a-slide-out-navigation-like-facebook-and-path
I have two subviews that are added to the navigation controller, The drawer is initialized as follows in viewDidLoad:
self.drawerViewController = [[DrawerViewController alloc] initWithNibName:#"drawer" bundle:nil];
self.drawerViewController.view.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.drawerViewController.view];
[self addChildViewController: self.drawerViewController];
[self.drawerViewController didMoveToParentViewController:self];
self.drawerViewController.view.frame = CGRectMake(0, 0, 150, self.view.frame.size.height);
then the contentview is initialized using a viewcontroller from my storyboard (and i call send subviewtoback to move the drawer behind it):
UIStoryboard* sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.contentViewController = [sb instantiateViewControllerWithIdentifier:#"HomeViewController"];
[self.view sendSubviewToBack:self.drawerViewController.view];
[self pushViewController:self.contentViewController animated:YES];
I move the main content view by animating the frame of the contentview which uncovers the drawer underneath:
[UIView animateWithDuration:SLIDE_TIME delay:0 options:UIViewAnimationOptionBeginFromCurrentState
animations:^{self.contentViewController.view.frame = CGRectMake(150, 0, self.view.frame.size.width, self.view.frame.size.height);
}completion:nil];
Which works but if I do something like click the margin of the drawer and drag, the drawer can end up covering the entire screen in the iphone simulator or disappearing showing the black background (which is more easily reproduced when rotating the device while showing drawer). My question is why is the drawerview draggable and how do you prevent this?
Edit:
I have found the source of the dragging is from this addChildViewController line:
[self addChildViewController: self.drawerViewController];
However removing this doesnt allow users to click the table cells anymore.
The problem was using a navigation controller as a container of subviews. I don't think it's meant to be used this way so I ended up scrapping this and rewriting it with a uiviewcontroller container instead.

uiviewanimation works in ios 7 but gets clipped and offset in ios6

working on moving my app to IOS7, but i'm having a uiviewanimation problem.
Everything works fine in IOS7, but when i use uiviewanimation to "flip" between two views, the view looks wrong during the transition, but fine after. It's higher up, and a part of the bottom of the view is clipped. See attached picture.
When the animation completes, the view "jumps" down to its correct position. I'm at a loss...
the code i use to flip my view is:
newView = [[LocationCrudViewController alloc] initWithNibName:THE_VIEW bundle:nil];
.....
[UIView transitionWithView:self.window duration:0.5
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^ { self.window.rootViewController = newView; }
completion:nil];
Point worth noting - i used to do:
self.window addSubview:currentViewController.view];
as the view animation, and that worked, however i then got the warning message that Application windows are expected to have a root view controller at the end of application launch so i switched to the above code which, again, works fine in IOS7.
I'm reeeaaally hoping someone can help out here.
For those interested, here's what i ended up doing:
My views are defined as per normal (for me), no ios6/7 deltas are needed, in a nib with associated controllers.
I have created a "dummy" view, which takes up the entire screen but has no content.
In my application delegate, i create my dummy view and set it as root:
self.root = [[RootViewController alloc] initWithNibName:ROOT_VIEW_CONTROLLER bundle:nil];
self.window.rootViewController = root;
I can then add and remove subviews as i see fit, like this:
[currentViewController.view removeFromSuperview];
UIView transitionWithView:self.window duration:0.5
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^ {
[self.window addSubview:newViewController.view]; }
completion:nil];
This works great, and it makes my views go under the status bar in both IOS6 and IOS7, just as i want.
Hope this helps somebody.

iOS - Semi-transparent modal view controller

I want to present a view controller with a slightly transparent background modally over the current view, such that the first view is slightly visible under the modal view.
I set the alpha value of the modal view controller and set the modalPresentationStyle to UIModalPresentationCurrentContext, as suggested in another post.
The result is that the view background is transparent when animating up, but when view controller is in place it changes to opaque black. It goes back to being transparent while animating the dismissal.
How can I get it to be transparent when active ?
I have tested in iOS 6 and 7. The code I am using follows:
MyModalViewController *viewController = [[MyModalViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
[navController setNavigationBarHidden:YES];
self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
[self.navigationController presentViewController:navController animated:YES completion:NULL];
iOS 8 added a new modal presentation style specifically for this purpose:
presentedViewController.modalPresentationStyle = UIModalPresentationOverFullScreen
From the spec:
UIModalPresentationOverFullScreen
A view presentation style in which the presented view covers the screen. The views beneath the presented content are not removed from the view hierarchy when the presentation finishes. So if the presented view controller does not fill the screen with opaque content, the underlying content shows through.
If you are targeting ios 8 and above you can set the modal presentation style to "over current context" and you are done.
If ios 7 and below, you would have to create a custom transition style so that the presenting screen doesn't go blank after transition. That is rather complicated.
The solution I present offers a lot of flexibility: make a screenshot before showing the modal dialog and set that as the background image for the application window. By default, that background is black (that is what you see when the back view controller dissapears). Change the background to the screenshot of the app. Make the screenshot in the viewWillAppear or viewDidLoad method of your transparent view. This works even with push segues, not only modal dialogs, but you should avoid animations. In general, avoid animations which affect the position of the background view because those will make it seem like it snaps back into place when transition finishes. It is a good idea to reset the background to its previous black image on viewDidDissapear to avoid unwanted effects.
You can maintain a stack of such background images and you can do multiple "transparent" push seques. Or have some complex/deep menu which appears on top of some main screen. For these many reasons I think this solution is better than rolling your own transitioning code. It is more flexible and easier to implement, and you don't have to deal with the animations yourself.
The reason that the BG view controllers disappear after a modal is shown is that the default transition in iOS 7 removes the BG view after animation completed. If you define your own transition and you set your BG view not to be removed (just changing its alpha) then you will have the transparent modal view.
Same problem occured to me. I have solved it by looking at the following url about a custom alert controller. I managed to get it working even with a UINavigationController.
Swift
let viewController = UIViewController()
viewController.providesPresentationContextTransitionStyle = true
viewController.definesPresentationContext = true
viewController.modalPresentationStyle = .overCurrentContext
viewController.modalTransitionStyle = .crossDissolve
DispatchQueue.main.async {
self.navigationController?.present(viewController, animated: true, completion: nil)
}
Objective C
UIViewController *viewController = [UIViewController new];
viewController.providesPresentationContextTransitionStyle = true;
viewController.definesPresentationContext = true;
viewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
viewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
dispatch_async(dispatch_get_main_queue(), ^{
[self.navigationController presentViewController:viewController animated:true completion:nil];
});
Here is a solution.
Create your presenting view controller. Add a backView to this view controller's main view. Name this as backView.
In SecondViewController.m
-(void)viewDidLoad
{
// Make the main view's background clear, the second view's background transparent.
self.view.backgroundColor = [UIColor clearColor];
UIView* backView = [[UIView alloc] initWithFrame:self.view.frame];
backView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
[self.view addSubview:backView];
}
Now you have a view controller with half transparent background. You can add anything you want to the self.view , the rest will be half transparent.
After that, in FirstViewController.m
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:secondViewController animated:YES completion:nil];
My solution is this:
Create a custom transparent overlay UIView that comes over any view, navigationbar and tabbbar.
-In the navigation controller (or tabbar controller) that your view controller is embedded in I create a custom view with it's frame equal to the frame of the navigation controller's view.
-Then I set it offscreen by setting it's origin.y to navigationController.view.height
-Then I create 2 functions -(void)showOverlay and -(void)hideOverlay that animate the overlay view on and off screen:
- (void)hideOverlay{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
CGRect frm = self.helpView.frame;//helpView is my overlay
frm.origin.y = self.offscreenOffset; //this is an Y offscreen usually self.view.height
self.helpView.frame = frm;
[UIView commitAnimations];
}
- (void)showOverlay{
[self.view bringSubviewToFront:self.helpView];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
CGRect frm = self.helpView.frame;
frm.origin.y = self.onscreenOffset;
self.helpView.frame = frm;
[UIView commitAnimations];
}
-In my view controller I can just call
[(MyCustomNavCtrl *)self.navigationController showOverlay];
[(MyCustomNavCtrl *)self.navigationController hideOverlay];
And that's about it.
FYI: The syntax is now:
childVC.modalPresentationStyle = UIModalPresentationStyle.OverFullScreen
Why don't you try setting this in AppDelegate
self.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
then changing the alpha on the view being presented

iOS - properly animate between two UIViews using CATransition

I have a UIView already on my screen and i wish to "slide in" a new UIView from one of the four directions(left, right, up, down) depending on what kind of swipegesture that i detect. Getting the swipegesture info is already done and not a problem but now, lets say if I swipe to the left then i want another UIView instance to "slide in" from the right.
Specifically, as the new UIView is sliding in from the right, the old UIView starts to slide out of view sliding to the left until it is out of the view completely. In other words, i would like to have the effect taht you can see both UIViews during the animation until the original UIView is no longer visible. The same type of effect can be seen on your iPad, for example, as you are on your home screen and you swipe to the left - which slides in another screen of app icons from the right as your home screen slides out of view to the left. The only caveat that I would like to achieve would be that you cannot stop the transition midstream.
Anyway here is the code that i have so far - I think that i am close but would like to get some help on perhaps finishing what i need to accomplish here:
UIView *newView = [[UIView alloc] init];
newView.frame = CGRectMake(0, 0, TileView.frame.size.width, TileView.frame.size.height);
[TileView addSubView:view];
CATransition *transitionAnimation = [CATransition animation];
[transitionAnimation setDuration:1];
[transitionAnimation setType:kCATransitionPush];
[transitionAnimation setSubtype:kCATransitionFromRight];
[transitionAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
The UIView TileView is a subview of my viewController. Is there any other setting up to do for newView so that everything matches as far as screen placement? I think that the KCATransitionPush is the type of animation I am looking for but not 100% sure.
Any help to what I am missing here would be helpful.
try to set these two property also....
transitionAnimation.fromValue=[NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0.0, 0.0, 0.0)];
transitionAnimation.toValue=[NSValue valueWithCATransform3D:CATransform3DMakeTranslation(excursion, 0.0, 0.0)];

Resources