UIView transitions - iphone

I am using ViewControllers for my different views, this is currently how I am switching from page to page:
- (IBAction)switchToSecondPage:(id)sender
{
SecondPage * secondPage = [[SecondPage alloc] initWithNibName:nil bundle:nil];
[self presentViewController: secondPage animated:YES completion:NULL];
}
This is the typical new view coming up from the bottom of the screen. I can use this to change the transition style, but I only get a couple choices to chose from, and none of them are any good.
secondPage.modalTransitionStyle = UIModalTransitionStylePartialCurl;
I am looking for transitions that are similar to the original one you get (page slides up from bottom). So I want 'slides down from top' and 'slides from left/right'. Is there any way I can do this. I see all sorts of applications doing this but I haven't been successful in finding anything.

One way to do this is,
[self.view addSubview:secondPage.view];
secondPage.view.frame = frameOutSideCurrentView;//Frame is set as outside the screen
[UIView animateWithDuration:1.0f
animations:^{
//actual frame needed with an animation.
secondPage.view.frame = originalFrame;
}
completion:^(BOOL finished) {
//if you need to anything specific once the animation is completed.
}];
Another way to do is by using this. TransitionController is custom implementation which helps to do this. In case you are facing issue with above code, use the category methods in this implementation. There are methods such as,
- (id)initWithViewController:(UIViewController *)viewController;
- (void)transitionToViewController:(UIViewController *)viewController
withOptions:(UIViewAnimationOptions)options;
which can be used to achieve this.

Related

Application Design - Menu system

I have a UIViewcontroller that has a UITableView and and a couple of buttons, (add and done)
When the user clicks add I need to get some details (which represent a notification they are setting in the app).
Details like notification name, a number, target score etc...
What is the best way to get this info, is it a good idea to use a UIView and animate it onto the screen with some textfields or something like that?
Any good cocoa controls you can recommend?
Problem is my app already transitions from the rootview controller to the notification input controller modally, I was trying to get a simple UI to just enter data, I could use UIAlertViews but they are so ugly....
based on your comment above:
CustomUIView *inputView = [UIView alloc]initWithFrame:CGRectMake(offscreenRect)];
inputView.alpha = 0;
self.notificationInputController.userInactionEnabled = NO;
[UIView animateWithDuration:.5
animations:^{
inputView.alpha = 1;
inputView.rect = CGRectMake(onScreenRect);
}
completion:^(BOOL finished) {
[self.notificationInputController addSubView:inputView];
self.notificationInputController.userInactionEnabled = YES;
}];

UIView transition causing crash

- (IBAction)StartGame:(id)sender
{
MainGameDisplay *secondPage = [[MainGameDisplay alloc] initWithNibName:nil bundle:nil];
[self.view addSubview:secondPage.view];
secondPage.view.frame = CGRectMake(568, 0, 568, 320);//(N = horizontal, N = vertical)
[UIView animateWithDuration:1.0f
animations:^{
//actual frame needed with an animation.
secondPage.view.frame = CGRectMake(0, 0, 568, 320);
}
completion:^(BOOL finished) {
//ENTER HERE ANYTHING TO RUN AFTER ANIMATION IS COMPLETED:
[self presentViewController: secondPage animated:NO completion:NULL];
//This will make the next page load correctly after the transition, otherwise you cannot. interact with anything.
}];
}
This works perfectly for entering the view. Without [self presentViewController: secondPage animated:NO completion:NULL];, you cannot interact with the new page, any button you click causes it to crash.
If I return back to the first page, doing it normally, it's fine, but if I click StartGame again, the program changes views and then simply crashes. The problem is with the line [self.view addSubview:secondPage.view];, if I comment this out, the program doesn't crash but when it changes views it doesn't transition and instantly appears.
The transition is also pretty laggy/glitchy in landscape mode, perfect in portrait though.
Here you are Adding secondPage on currentView as aSubview. and Again your presenting it.
I think it causing some memory related thing may be some other thing(it would be much clear if you put some crash log here in your question). But i'll suggest you no need to present secondPage Again .Here is your Code i made Single Line Change here .
- (IBAction)StartGame:(id)sender
{
MainGameDisplay *secondPage = [[MainGameDisplay alloc] initWithNibName:nil bundle:nil];
[self.view addSubview:secondPage.view];
secondPage.view.frame = CGRectMake(568, 0, 568, 320);//(N = horizontal, N = vertical)
[UIView animateWithDuration:1.0f
animations:^{
//actual frame needed with an animation.
secondPage.view.frame = CGRectMake(0, 0, 568, 320);
}
completion:^(BOOL finished) {
//ENTER HERE ANYTHING TO RUN AFTER ANIMATION IS COMPLETED:
You should comment below sinlge because you have already added secondPage as a Subview on currentView.so further no need to present it again.
// [self presentViewController: secondPage animated:NO completion:NULL];
//This will make the next page load correctly after the transition, otherwise you cannot. interact with anything.
}];
}
Edit: For Landscape Mode you should change coordinate while you are setting the frame secondPage view . i think here you are creating this view for 4 inch Devices.
here you can do this by setting some checks as this
if(checkIfDeviceIsInlandscae)
{
secondPage.view.frame = CGRectMake(568, 0, 568, 320);
}
else
{
secondPage.view.frame = CGRectMake(320, 0, 320, 568);
}
Inside the animation block change the frame according to the orientation, as i did above tow line.
One problem is by calling both presentViewController: and addSubview: you are adding the view twice. I suspect you find it necessary to call presentViewController: because it invokes viewDidAppear: and you're using that to hook up the UI in secondPage. I'd put a logging statement in MainGameDisplay's viewDidAppear: method and see when it is getting called.
One fix may be to just replace [self presentViewController: secondPage animated:NO completion:NULL] with [secondPage viewDidAppear:NO].
Your problem is one of memory allocation/deallocation. You're not retaining secondPage anywhere, and as such it will be deallocated after the StartGame method logic is completed. This deallocation will in turn deallocate MainGameDisplay's ivars/properties too, including MainGameDisplay.view. This will all happen before you start to interact with the displayed view, so the moment you try to change values or interact with the no-longer-existent view, you're going to crash with an EXC_BAD_ACCESS error.
If you truly want to manage MainGameDisplay.view outside of the view controller, you'll need to retain secondPage in an ivar or member variable in your parent class:
ParentClass.m:
#interface ParentClass ()
{
MainGameDisplay *_secondPage;
}
#end
...
- (IBAction)StartGame:(id)sender
{
_secondPage = [[MainGameDisplay alloc] initWithNibName:nil bundle:nil];
[self.view addSubview:_secondPage.view];
...
}
However, this is not generally a recommended design pattern. It's the responsibility of a view controller to manage its view, particularly layout changes that might be made, animations in how it's displayed, etc. You're violating the encapsulation responsibilities of MainGameDisplay. You should consider doing whatever view management you need to do inside of MainGameDisplay.
I would recommend reading through the View Controller Programming Guide for iOS. It will explain the fundamentals around what you're trying to do, and best practices for doing it.

UIView TransitionFromView disables scrolling

Hey there StackOverflow! I've finished programming my app, and everything is working fine- so I've decided that since the function part is done, I want to start working on form. However, I have a bit of code that's giving me trouble, and I'm not sure why. My app has two views that I switch between. In viewDidLoad, I have these two lines of code:
[PlannerView setScrollEnabled:YES];
[PlannerView setContentSize:CGSizeMake(320, 735)];
and then later, I switch between the main view and planner view when a button is pressed, like this:
if (isPlannerView) {
// [self setView:MainView];
[UIView transitionFromView:PlannerView
toView:MainView
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromRight
completion:^(BOOL finished){
[self setView:TimerView];
}];
isPlannerView = NO;
} else {
[UIView transitionFromView:MainView
toView:PlannerView
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromLeft
completion:^(BOOL finished){
}];
// [self setView:PlannerView];
isPlannerView = YES;
}
Now, when I use hte commented line of code (self setview), it will scroll with no problems. However, when I use UIView transitionFromView, it no longer scrolls. Any idea what is going wrong here?
The documentation for transitionFromView:toView:duration:options:completion: says:
This method modifies the views in their view hierarchy only. It does
not modify your application’s view controllers in any way. For
example, if you use this method to change the root view displayed by a
view controller, it is your responsibility to update the view
controller appropriately to handle the change.
So make sure that viewDidLoad: is actually being called. It also states:
During an animation, user interactions are temporarily disabled for
the views being animated. (Prior to iOS 5, user interactions are
disabled for the entire application.) If you want users to be able to
interact with the views, include the
UIViewAnimationOptionAllowUserInteraction constant in the options
parameter.
So make sure that user-interaction is enabled on the view after the animation is finished.
completion:^(BOOL finished){
[PlannerView setUserInteractionEnabled:YES];
}];
Source: UIView Class Reference

What is wrong with this iOS animation block?

+ (void) AnimateSwitchingWithParent: (UIViewController *) ParentController From: (UIViewController *) From To: (UIViewController* ) To {
To.view.frame = ParentController.view.bounds;
[UIView transitionFromView:From.view toView:To.view
duration:1
options:UIViewAnimationOptionTransitionFlipFromLeft completion:NULL];
ParentController.view = To.view;
[To viewWillAppear:true];
}
this is my function to make animation that will be called if want to change view from 1 view to another view, but I have problem, I have a viewController named filter, at there I have Button called Reset that will reset all of content inside
but to show that the reset have done, I want to call
[self AnimateSwitchingWithParent:self From:self To:self];
but the result is My View was blank. how can it be? any one have another way?
If you have to flip the current view controller's view while resetting content, use the transitionWithView:duration:options:animations:completion: method.
Example
[UIView transitionWithView:self.view
duration:1.0f
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^(void) {
[self resetStuff];
}
completion:nil];
Side Note
You current implementation in the question will be useful to switching views in the view hierarchy. Say From.view is the subview of ParentController.view then the statement below will replace From.view with To.view as the subview of ParentController.view.
[UIView transitionFromView:From.view toView:To.view
duration:1
options:UIViewAnimationOptionTransitionFlipFromLeft completion:NULL];
You definitely don't need to do this,
ParentController.view = To.view;
Doing that will replace the ParentController's view which might be different from what you intended and definitely in contradiction to the transition animation on the line before.
You must definitely not be calling,
[To viewWillAppear:true];
directly.
To my understanding you should be able to remove the last two lines.

Animating UIView while pushing a UINavigationController

following situation.
i have an app that uses a UINavigationController for navigating.
For a push of a special Navigation Controller i want a custom Animation, a zoom out.
What i have is looking good so far, the only problem is, that the "old" Viewcontroller disappears before the animation starts, so the new viewcontroller zooms out of "nothing" instead of viewing the old viewcontroller in the background.
For better viewing i created a simple sample app: download
Does anybody know, how to animate the new viewcontroller (image3) that the old view controller(image1) stays in the background while animating (image 2)?
/* THIS CANNOT BE CHANGED */
AnimatedViewController *animatedViewController = [[AnimatedViewController alloc] initWithNibName:#"AnimatedViewController" bundle:nil];
/* THIS CAN BE CHANGED */
animatedViewController.view.transform = CGAffineTransformMakeScale(0.01, 0.01);
[UIView beginAnimations:#"animationExpand" context:NULL];
[UIView setAnimationDuration:0.6f];
animatedViewController.view.transform=CGAffineTransformMakeScale(1, 1);
[UIView setAnimationDelegate:self];
[UIView commitAnimations];
/* THIS CANNOT BE CHANGED */
[self.navigationController pushViewController:animatedViewController animated:NO];
Additional information: my app isn't that simple. i use three20 framework for my app but the pushing and creating of the view controllers is simply what three20 does. i only can hook into the part between (THIS CAN BE CHANGED in my code). i cannot change the code before and after this (except with a lot of researching).
I whipped this up very quickly. The idea is to call pushViewController after the scale animation is completed.
-(IBAction)animateButtonClicked:(id)sender {
animatedViewController = [[AnimatedViewController alloc] initWithNibName:#"AnimatedViewController" bundle:nil];
animatedViewController.view.transform = CGAffineTransformMakeScale(0.01, 0.01);
[UIView animateWithDuration:0.6
animations:^{
[self.view addSubview:animatedViewController.view];
animatedViewController.view.transform=CGAffineTransformMakeScale(1, 1);
}
completion:^(BOOL finished){
[animatedViewController.view removeFromSuperview];
[self.navigationController pushViewController:animatedViewController animated:NO];
}];
}
Ok, one way to do this (a bit ugly) is to do the animation and upon the completion of the animation, do the pushViewController. When you do the animation, you need to animate up what the about-to-be-presented view controller's screen would look like. Since the animation ends with the new view, when the new view comes to the screen, nothing should change because its the same as the just animated view.