ECSlidingViewController problems with topview animation - ios

I'm using ECSliding and I have this problem!
In my project there are this files:
InitViewController (ECSlidingController)
FirstViewController (UIViewController)
SecondViewController (UIViewController)
LeftMenuViewController (UIViewController)
I use InitView to instatiate my FirstView as the topview.
In my FirstView there is a button, when pressed sets SecondView as topview.
Is it possible to animate the changing topview like I'm opening a new view?
or how can I open a new view that uses ECSliding like the first one?
I'm using this code to change topview:
self.slidingViewController.topViewController = second;
[self.slidingViewController resetTopView];
The animation that I want could just be the default one, like:
[self presentViewController:(*UIViewController) animated:YES completion:nil];

Subclass ECSlidingViewController. I call my subclass DeckController:
In DeckController.h:
- (void)setTopViewController:(UIViewController *)topViewController withTransition:(CATransition*)transition;
In DeckController.m:
- (void)setTopViewController:(UIViewController *)topViewController withTransition:(CATransition*)transition {
self.topViewController = topViewController;
[UIView animateWithDuration:0.25f animations:^() {
[[self.view layer] addAnimation:transition forKey:#"topViewTransition"];
}];
}
Then in the view controller that wants to switch to the new top view, do something like this:
CATransition *animation = [CATransition animation];
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromRight];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[animation setFillMode:kCAFillModeBoth];
[animation setDuration:.25];
DeckController *deck = (DeckController*)self.slidingViewController;
[deck setTopViewController:newTopViewController withTransition:animation];

Probably your best option is to use the animation methods of the sliding view controller. Animate the top view off screen, in the completion block change the top view controller (to second) then start a new animation to animate the top view back onto screen.
[self.slidingViewController anchorTopViewOffScreenTo:...
animations:...
onComplete:^{
self.slidingViewController.topViewController = second;
[self.slidingViewController resetTopView];
}];

I just use same operation as when Im clicking on a menuitem in my left menu.
[self.anchorTopViewOffScreenTo:ECRight animations:nil onComplete:^{
CGRect frame = self.topViewController.view.frame;
self.topViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"secondVC"];
self.topViewController.view.frame = frame;
[self resetTopView];
}];
Just generalize this, and you can call it everywhere. It does the animation by itself.
You can do as #Alex, but if you don't have to do some custom animation, this is all you need.
NB. in my example Im using this in the initViewController (for which is the ECSlidingViewController, therefore i'm sending to self), for forcing user to a specific viewController. If you need to change view in any subViewControllers you just sending to self.slidingViewController like the example below:
[self.slidingViewController anchorTopViewOffScreenTo:ECRight animations:nil onComplete:^{
CGRect frame = self.slidingViewController.topViewController.view.frame;
self.slidingViewController.topViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"secondVC"];
self.slidingViewController.topViewController.view.frame = frame;
[self.slidingViewController resetTopView];
}];

You can manually create the animation then set the topViewController at the end so that the sliding view controller is in the state that you expect.
SecondTopViewController *secondTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondTop"];
secondTopViewController.view.frame = self.slidingViewController.view.bounds;
secondTopViewController.view.alpha = 0;
// temporarily add the second top view so that we can animate it in.
[self.slidingViewController.view addSubview:secondTopViewController.view];
[UIView animateWithDuration:0.5 animations:^{
secondTopViewController.view.alpha = 1;
} completion:^(BOOL finished) {
// remove the second top view.
[secondTopViewController.view removeFromSuperview];
// let sliding view controlller take over from here
self.slidingViewController.topViewController = secondTopViewController;
}];
See my working example here: https://github.com/enriquez/ECSlidingViewController/tree/so-16658539

#Michael-Enriquez's answer converted to swift.
let viewController = (self.storyboard?.instantiateViewControllerWithIdentifier("ViewController"))! as? ViewController
let navController = UINavigationController(rootViewController: viewController!)
navController.view.frame = self.slidingViewController().view.bounds
navController.view.alpha = 0
self.slidingViewController().view.addSubview(navController.view)
UIView.animateWithDuration(0.25, animations: {
navController.view.alpha = 1
}, completion: {(finished:Bool) -> Void in
navController.view.removeFromSuperview()
self.slidingViewController().topViewController = navController
})

Related

Flicker while dismissing UIViewController

I have a UIViewController I'm presenting using a custom transition (for blurring). When I press the close button, I want the UIViewController to fade out. I reduce the opacity of the view and it fades out fine. And in the completion block, I dismiss the UIViewController. It gets dismissed, but there's a flicker soon after the dismiss is done and over with.
Here's what I'm doing:
- (IBAction)closePressed:(id)sender {
[CATransaction setCompletionBlock:^{
[self dismissViewControllerAnimated:NO completion:nil];
}];
CABasicAnimation *fadeOut = [CABasicAnimation animationWithKeyPath:#"opacity"];
fadeOut.fromValue = [NSNumber numberWithFloat:1.0];
fadeOut.toValue = [NSNumber numberWithFloat:0.0];
fadeOut.duration = 0.4f;
[self.view.layer addAnimation:fadeOut forKey:#"fadeOut"];
}
Can't paste a screenshot or anything as it happens quickly. There's a flicker before the parent UIViewController is shown.
When you animate via CAAnimation you are actually animating the presentation layer of the view, not the actual view. So when animation ends, you'll end up with the view as it was before the animation started.
To avoid that add this two lines before addAnimation:forKey:
fadeOut.removedOnCompletion = NO;
fadeOut.fillMode = kCAFillModeForwards;
Have you tried as like below?
[UIView animateWithDuration:0.4 animations:^
{
self.view.alpha = 0.0;
} completion:^(BOOL finished)
{
[self dismissViewControllerAnimated:NO completion:nil];
}];
Instead of above method, You can use self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
Try switching your opaque setting for that viewcontroller to YES / NO
Default value is YES, so you probably want to try out NO

How to change the transition animation from bottom to top in navigation controller?

I am new to iOS. I am trying to change the transition animation in navigation controller to load a new UIView controller from bottom to top, using Segue. I believe it will not be too hard to implement but may be I am not able to understand it.
I could not find any solution in other posts.
Here's the code I've been trying:-
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"alarmSegue"]) {
tab2ViewController *destViewController = segue.destinationViewController;
UIView *destView = destViewController.view;
destViewController.selectionName = #"alarms";
[sender setEnabled:NO];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
[UIView animateWithDuration:0.0
delay:0.0
options: UIViewAnimationOptionCurveLinear
animations:^{
[destView setTransform:CGAffineTransformMakeTranslation(0, -1000)];
//[destView setFrame:CGRectMake(0, 440, 400, 45)];
//destView.frame = CGRectMake(0, 0, 320, 460);
}
completion:^(BOOL finished){
[sender setEnabled:YES];
}];
[UIView commitAnimations];
}
}
I just want to implement a SIMPLE transition from bottom to top, using Segue. I want to set some properties of destination controller as well.
Replace the code between [UIView beginAnimations:nil context:nil]; and [UIView commitAnimations]; (including those two lines as well) with the following:
CGAffineTransform baseTransform = destView.transform; //1
destView.transform = CGAffineTransformTranslate(baseT,0,destView.bounds.size.height); //2
[UIView animateWithDuration: 0.5 animations:^{
destView.transform = baseTransform; //3
}];
Make a reference of the original transform.
Push our view down without an animation so we can animate it back up
Set the original transform back to the view. This time, it'll animate
You can further add the delay, options and completion parameters to that UIView Animation method. Xcode will probably help you with the autocompletes on those.
Well you are nearly there.
You need to change two things mainly:
1 Change the initial position of the view. You want the view to appear from bottom to top, so initially your view should be at the bottom. This piece of code should be written before the animation.
[destView setTransform:CGAffineTransformMakeTranslation(0, -1000)];
2 Then you need to slide from bottom to the original position , hence inside the animation block:
[destView setTransform:CGAffineTransformMakeTranslation(0, 0)];
One more suggestion, I guess you are using a newer version of iOS(above iOS4) instead of using animation blocks use UIView's animation method
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
For further info, refer description.
EDIT :
According to your edit on question, you are looking to change the transition animation for NavigationController in the app using storyboard. For that you could use Custom Segue. You will have to create a custom segue, a class that subclasses UIStorySegue and override its perform method like this:
-(void)perform {
//UIViewAnimationOptions options;
UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
UIViewController *destinationController = (UIViewController*)[self destinationViewController];
CATransition* transition = [CATransition animation];
transition.duration = 0.9f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
transition.subtype = kCATransitionFromTop; //kCATransitionFromLeft, kCATransitionFromRight, kCATransitionFromTop, kCATransitionFromBottom
[destinationController.view.layer addAnimation:transition forKey:kCATransition];
[sourceViewController presentViewController:destinationController animated:NO completion:nil];
}
You have to change the segue class to this custom segue in storyboard as well, to make it function.
Try using transition effects
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"alarmSegue"]) {
CATransition transition = [CATransition animation];
transition.duration = 0.5;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush;
transition.subtype = direction;
[self.view.layer addAnimation:transition forKey:kCATransition];
tab2ViewController *destViewController = segue.destinationViewController;
UIView *destView = destViewController.view;
destViewController.selectionName = #"alarms";
[sender setEnabled:NO];
}
}

Custom ViewController Transition Remove Gap Between Views

Hi I have a custom transition between two view controllers and I want to remove the black gap between them when it makes the transition. What can I do to do this? Thank you! Here is how the transition is performed currently with a CATransition and a picture of the gap.
- (void)bottomButtonScreen4:(UIGestureRecognizer *)gestureRecognizer {
NSLog(#"Swipe Up Worked");
settingsViewController = [[SettingsViewController alloc] init];
CATransition* transition = [CATransition animation];
transition.duration = 0.5;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromTop;
[self.navigationController.view.layer addAnimation:transition forKey:nil];
settingsViewController = [self.storyboard instantiateViewControllerWithIdentifier: #"settingView"];
[self.navigationController pushViewController:settingsViewController animated:NO];
}
Using this transition, there's only so much you can do. You'll notice (if you make it slow enough) that as the new view moves in, it's also fading in and the outgoing view is fading out. You can get rid of the black bar by setting the window's background color to the same color as your incoming view's background color, but you'll also see the outgoing controller's view fade to that color as it goes out. Check that out, and see if that's a look you can live with.
self.view.window.backgroundColor = settingsViewController.view.backgroundColor;
P.S. You should get rid of the line where you alloc init settingsViewController. It isn't doing anything now, and it was the wrong way to get that instance anyway.
After Edit:
Another way to do this that gets rid of the black bar problem, is to use animateWithDuration like this:
-(IBAction) pushViewControllerFromTop {
CGFloat height = self.view.bounds.size.height;
UIViewController *settingsViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Blue"];
settingsViewController.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y - height, self.view.frame.size.width, self.view.frame.size.height);
[self.view.superview addSubview:settingsViewController.view];
[UIView animateWithDuration:.5 animations:^{
self.view.center = CGPointMake(self.view.center.x, self.view.center.y + height);
settingsViewController.view.center = CGPointMake(settingsViewController.view.center.x, settingsViewController.view.center.y + height);
} completion:^(BOOL finished) {
[self.navigationController pushViewController:settingsViewController animated:NO];
}];
}

UIViewController half screen "drawer slide" animation

I am trying to have a UIViewController that appears with a "slide" animation from the right. Not like a Push segue, not like the Facebook app. I want the new ViewController to slide ON TOP of the current one (not push it away), but only cover PART of the screen, leaving the other part showing the first ViewController.
What I have tried: The closest that I have gotten is by creating a custom segue with the following:
- (void)perform
{
__block UIViewController *src = (UIViewController *) self.sourceViewController;
__block UIViewController *dst = (UIViewController *) self.destinationViewController;
CATransition* transition = [CATransition animation];
transition.duration = .50;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromRight;
[src.navigationController.view.layer addAnimation:transition forKey:#"SwitchToView1"];
[src.navigationController pushViewController:dst animated:NO];
}
This achieves the animation that I am going for, but it covers the entire first ViewController. How would I make it stop at a certain point and not cover the entire thing?
I am using Storyboards, and I this is my first time trying any sort of new animation.
You can try doing it in your source view controller, and changing the frame for your destnation (the x axis) something like:
- (void) perform {
UIViewController *dst = (UIViewController *) self.destinationViewController;
[dst.view setFrame:CGRectMake(160, 0, YOUR_DST_WIDTH, YOUR_DST_HEIGHT)];
//your animation stuff...
[self addChildViewController:dst];
[self.view addSubview:dst.view];
[dst didMoveToParentViewController:self];
}
And that should do it!
Let me know if it didn't...
UPDATE!:
#CaptJak Hey, sorry that didn't work out for you.. I wrote the following code, and it works without any problems here.. I linked it to a button click.. try it and let me know! (PS: I added animations too!).
ViewController *tlc = [self.storyboard instantiateViewControllerWithIdentifier:#"MainViewController"];
[tlc.view setFrame:CGRectMake(-320, 0, self.view.frame.size.width, self.view.frame.size.height)];
[self addChildViewController:tlc];
[self.view addSubview:tlc.view];
[tlc didMoveToParentViewController:self];
[UIView animateWithDuration:0.3 animations:^{
[tlc.view setFrame:CGRectMake(-160, 0, self.view.frame.size.width, self.view.frame.size.height)];
}];
Using the answer given by Albara, I was able to also create a segue with the same animation. The custom segue is as follows:
- (void)perform
{
UIViewController *src = (UIViewController *)self.sourceViewController;
UIViewController *dst = (UIViewController *)self.destinationViewController;
[dst.view setFrame:CGRectMake(380, 0, dst.view.frame.size.width, dst.view.frame.size.height)];
[src addChildViewController:dst];
[src.view addSubview:dst.view];
[dst didMoveToParentViewController:src];
[UIView animateWithDuration:0.5 animations:^{
[dst.view setFrame:CGRectMake(300, 0, src.view.frame.size.width, src.view.frame.size.height)];
}];
}
Just a matter of renaming, really.
I just created NDOverlayViewController to do something like this. Actually it can overlay/slide one view controller over another from any edge with variable offset, extent and animation options. I created it as an experiment but maybe it will be helpful to somebody?

presentViewController animation from side

I have a single view App and want to show a new ViewController when pressing a nav bar button in the right hand side. I call this VC by this code:
- (IBAction)createEntryButton:(id)sender {
CreateEntryViewController *vc2 = [[CreateEntryViewController alloc] init];
[self presentViewController:vc2 animated:TRUE completion:nil];
}
This animation, however, brings the vc2 in from the bottom which seems counter-intuitive according to my UI. So my question is:
How can I make my vc2 appear from the right instead of the bottom with presentViewController?
Thanks.
the cleanest would be to use a navigationController for pushing and popping views..
if you are already in a NavigationController
[self.navigationCtroller pushViewController:vc2 animated:TRUE completion:nil]
if you aren't, adapt the code where your view controller is added to the window. If your VC is the rootWindowController and you are not using storyboarding, this is likely in your AppDelegate
if you use storyboards, adapt the storyboard so you are inside a navigation controller
ELSE if you don't want that for any reason: :) just manually animate in the 2. VC's view using [UIView animate:vc2.view ....]
written inline -- method names don't match but shows general approach:
UIView *v = vc2.view;
CGRect f = v.frame;
f.origin.x += self.view.frame.size.width; //move to right
v.frame = f;
[UIView animateWithDuration:0.5 animations:^{
v.frame = self.view.frame;
} completion:^(BOOL finished) {
[self presentViewController:vc2 animated:NO completion:nil];
}];
in the completion block present the view controller vc2 non-animated as you already did that yourself
This helped me,
- (void)presentNewViewController{
NewViewController *objNewViewController =[[NewViewController alloc]initWithNibName:#"NewViewController" bundle:nil];
UIView *tempNewVCView = [UIView new];
tempNewVCView = objNewViewController.view;
tempNewVCView.frame = self.view.frame;
CGRect initialFrame = self.view.frame;
initialFrame.origin.x = self.view.frame.size.width;
tempNewVCView.frame = initialFrame;
[self.view addSubview:tempNewVCView];
[UIView animateWithDuration:0.3 animations:^{
tempNewVCView.frame = self.view.frame;
} completion:^(BOOL finished) {
[self presentViewController:objNewViewController animated:NO completion:^{
}];
}];
}

Resources