rootViewController set but comes up as incorrect orientation - ios

My situation is very similar to this question . I have an app that is universal where iPhone is in portrait orientation and the iPad is in Landscape and I switch between all of my main screens using the appDelegate.window.rootViewController = newScreen; The iPhone app works perfectly. The iPad app will sometime throw the screen up in portrait orientation instead of landscape. Here is some sample transition code:
AppDelegate* appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
ViewController* v = nil;
if (IS_IPAD()) {
v = [[ViewController alloc] initWithNibName:#"ViewController-iPad" bundle:nil];
}else{
v = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
}
[appDelegate.window setRootViewController:(UIViewController*)v];
I also tried this from this other question :
AppDelegate* appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
ViewController* v = nil;
if (IS_IPAD()) {
v = [[ViewController alloc] initWithNibName:#"ViewController-iPad" bundle:nil];
}else{
v = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
}
[UIView
transitionWithView:appDelegate.window
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^(void) {
BOOL oldState = [UIView areAnimationsEnabled];
[UIView setAnimationsEnabled:NO];
[appDelegate.window setRootViewController:(UIViewController*)v];
[UIView setAnimationsEnabled:oldState];
}
completion:nil];
But nothing has fixed it.
Also tried using [appDelegate.window makeKeyAndVisable] and [appDelegate.window makeKeyWindow] in the hopes that this would "shock" it into doing the correct orientation.

I've got it!
Here's what my transition block looks like. The key thing I did was copy the transform (the thing that does the actual rotation) from the CALayer. Note that you'll have to include the Quartz framework and #import <QuartzCore/QuartzCore.h> at the top of your file.
[UIView transitionWithView:self.window
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
BOOL oldState = [UIView areAnimationsEnabled];
[UIView setAnimationsEnabled:NO];
target.view.layer.transform = window.rootViewController.view.layer.transform;
window.rootViewController = target;
[UIView setAnimationsEnabled:oldState];
} completion:nil];

Related

The right way for creating a custom popup / alert UIView / UIViewController

I've been developing for iOS for quite a while now, but I always got problems with custom alerts / popups, I just don't know what is the right way to add a custom view as a popup on top of all other views in app.
I've checked online and there are several ways to do it, but what is the best way for creating those custom alerts / popups?
There is a CustomViewController class and this is how I've created it and add it as a popup:
Create a new UIViewController
Add a UIView inside the UIViewController's XIB file as a child of self.view (This will hold the popup elements inside)
Add this method inside the UIViewController for presenting the view:
- (void)presentViewController
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.windowLevel = UIWindowLevelStatusBar;
self.window.screen = [UIScreen mainScreen];
[self.window makeKeyAndVisible];
UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
[mainWindow setUserInteractionEnabled:NO];
[self.window addSubview:self.view];
self.view.alpha = 0.0f;
self.backgroundImage.image = [self takeSnapshot];
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.view.transform = CGAffineTransformIdentity;
self.view.alpha = 1.0f;
} completion:nil];
}
Add this method inside the UIViewController for removing the view:
- (void)dismissShareViewController
{
[UIView animateWithDuration:DEFAULT_ANIMATION_DURATION
animations:^{
self.view.alpha = 0.0f;
} completion:^(BOOL finished) {
[self.view removeFromSuperview];
self.window = nil;
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
[mainWindow setUserInteractionEnabled:YES];
}];
}
Usage:
Creating a property for the UIViewController
#property (strong, nonatomic) CustomViewController *viewController;
Initialize and present
- (void)showCustomViewController
{
self.viewController = [[CustomViewController alloc] init];
[self.viewController presentViewController];
}
The problem is that I always get a Received Memory Warning. Also I've added a - (void)dealloc method inside the CustomViewController to know if the UIViewController is releasing properly, but for some reason the dealloc method is getting called right after the presentViewController and not after the dismissShareViewController as it should.
Another thing that I want to achieve: This CustomViewController has no UIStatusBar and when I try to present MFMailComposeViewController, I always get the MFMailComposeViewController to show without a UIStatusBar or with white status bar, but I can't change it to default back again. I've tried several question here on StackOverflow but without any luck, it just won't change.
Putting a UIView or UIWindow above Statusbar
Please, for once and for all, someone will help me with it.
UIAlertView is a subclass of UIView. If you wanted to create a custom alert view, I would also subclass UIView so that it is easy to swap out your existing UIAlertView's with your new custom view.
You can place your custom alert view atop your topmost UIWindow to cover everything.
#interface MyAlertView : UIView
- (void)duplicateAllTheFunctionsOfUIAlertViewHere;
#end
#implementation MyAlertView : UIView
- (id)initWithFrame:(CGRectMake)frame {
// add your custom subviews here
// An example of a custom background color:
self.backgroundColor = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.5];
}
- (void)duplicateAllTheFunctionsOfUIAlertViewHere {
//re-implement all the functionality in your custom ways
}
- (void)show
{
UIView* superview = [UIApplication sharedApplication].keyWindow;
self.frame = superview.bounds;
[superview addSubview:self];
// Do an animation if you want to get fancy
}
#end
Usage in a view controller:
- (void)showAlertView
{
UIView* alertView = [[MyAlertView alloc] initWithTextAndButtons:#"blah"];
[alertView show];
}

Sometimes UIView animateWithDuration happens immediately

Randomly my app will not animate at all. My app has a sound bar that gets updated every 0.1 seconds with an animation. Usually when I start the app the animations will work all pretty and everything but then at a random point usually after I transition to another view controller (via setViewControllers) it all of a sudden stops animationg. It's not just this animation but every animation in my app excluding setViewControllers.
Here is my code where I call setViewControllers:
- (void)goToController:(GeneralViewController *)vc animate:(BOOL)animated sub:(BOOL)sub{
if(animated){
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSMutableArray *viewController = [NSMutableArray arrayWithArray:[delegate.navController viewControllers]];
if(viewController.count > 0){
viewController[0] = vc;
}else{
[viewController addObject:vc];
}
CATransition* transition = [CATransition animation];
transition.duration = 0.2;
transition.type = kCATransitionPush;
if(sub)
transition.subtype = kCATransitionFromRight;
else
transition.subtype = kCATransitionFromLeft;
[delegate.navController.view.layer addAnimation:transition forKey:kCATransition];
[delegate.navController setViewControllers:viewController animated:FALSE];
self.colorStyle = MusicPlusColorStyleLight;
}else{
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSMutableArray *viewController = [NSMutableArray arrayWithArray:[delegate.navController viewControllers]];
if(viewController.count > 0){
viewController[0] = vc;
}else{
[viewController addObject:vc];
}
[delegate.navController.view.layer removeAnimationForKey:kCATransition];
[delegate.navController setViewControllers:viewController animated:FALSE];
}
}
Here is the code I use to animate the sound bar:
[UIView animateWithDuration:0.1 delay:0.0 options:UIViewAnimationCurveLinear | UIViewAnimationOptionBeginFromCurrentState
animations:^{
meterViewColor.frame = CGRectMake(0, (meterView.frameSizeHeight - (level*meterView.frameSizeHeight)), meterView.frameSizeWidth, (level*meterView.frameSizeHeight));
}
completion:nil];
I have checked and the code is running on the main thread. The CPU was on average around 10% and the Memory was 25 MB. So I am really baffled as to why it stops working sometimes. Has anyone else experienced this?
UPDATE: Sorry to say but the answer I posted was incorrect. It still isn't working. I have removed my answer and attached it bellow:
When creating the animation I added:
[transition setDelegate:self];
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag{
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[delegate.navController.view removeTransition];
}
- (void) removeTransition {
if (!CGAffineTransformIsIdentity(self.transform)) {
self.transform = CGAffineTransformIdentity;
}
}
UPDATED: I just undeleted my answer as it seems one of the properties transitionTransform should have been just transform. So it seems the animation was happening instantly because self.transform != CGAffineTransformIdentity. Even though self was the UINavigationController view it was still the superview of the views I was trying to animate.
Turns out the animation either wasn't being removed or was being removed at the wrong time.
When creating the animation I added:
[transition setDelegate:self];
And then in the delegate method:
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag{
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[delegate.navController.view removeTransition];
}
Where removeTransition was a category method on UIView defined as:
- (void)removeTransition {
if (!CGAffineTransformIsIdentity(self.transform)) {
self.transform = CGAffineTransformIdentity;
}
}

Animate change of rootViewController to SplitViewController?

I have a project that starts off with a tableView, however when the user taps the Setup button, I want to animate the change to a splitViewController.
I can easily change the rootViewController, however the animation isn't as advertised:
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"SetupViewController"];
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[UIView transitionWithView:self.navigationController.view
duration:0.75
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
app.window.rootViewController = controller;
}
completion:nil];
Is there a way I can animate this change of rootViewController?
It is a little hackie, but try setting the root before the animation and back again, so the new ViewController gets the right size when you start the animation:
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"SetupViewController"];
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
UIViewController *currentController = app.window.rootViewController;
app.window.rootViewController = controller;
app.window.rootViewController = currentController;
[UIView transitionWithView:self.navigationController.view.window
duration:0.75
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
app.window.rootViewController = controller;
}
completion:nil];
This solution worked for me.

App crashes on iPhone 5 when calling the Viewcontroller in delegate

I have a project that works well in other simulators including The New iPad. However, with the iPhone5, it crashes when calling the Viewcontroller in delegate
I don't know why this error happens. Please let me know if you discover any possible causes in the code below:
self.rootviewController = [[RootViewController alloc] initWithNibName:#"RootViewController" bundle:nil];
self.rootNavController = [[UINavigationController alloc]
self.rootNavController.navigationBar.hidden=YES;
[window addSubview:rootNavController.view];'
Please see image below:
Thank you very much
I think you do something wrong with the creation of your UINavigationController, try the following code to replace yours in your AppDelegate.m :
EDIT add code to display and remove splashscreen with UIViewController
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Create View Controller
RootViewController *rootViewController = [[RootViewController alloc] initWithNibName:#"RootViewController" bundle:nil];
// Create Navigation Controller
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
// Create Navigation Controller
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
// SplashScreen
[self displaySplashscreen];
return YES;
}
#pragma mark - SplashScreen Methods
- (void)displaySplashscreen
{
// Create View
self.splashscreenViewController = [[SplashscreenViewController alloc] init];
// Display Splashscreen
[_window addSubview:_splashscreenViewController.view];
// Dismiss Splashscreen
[self performSelector:#selector(dismissSplashscreen) withObject:nil afterDelay:3.0f]; // Modify the time
}
- (void)dismissSplashscreen
{
// Splashscreen Animation
[UIView animateWithDuration:0.5f
animations:^{
_splashscreenViewController.view.alpha = 0.0f;
} completion:^(BOOL finished) {
[_splashscreenViewController.view removeFromSuperview];
}];
}

Is it right to switch in between UIViewController that way?

I want to use my own controller for navigating in between uiviewcontrollers. So like that I can have custom transitions in between my views.
I did something which is working but I'm not sure if it is the right way? Could there be problems related to memory later?...I'm not sure everything is deallocated the right way.
Thanks for your help!
Here is my code:
In my AppDelegate, when it starts:
self.rootVC = [[[MenuView alloc] initWithNibName:#"MenuView" bundle:nil] autorelease];
[self.window addSubview:self.rootVC.view];
In my AppDelegate, the method for switching in between UIViewController:
-(void) changeRootController: (NSString*) ctrlName{
UIViewController *oldVC = self.curVC;
UIViewController *newVC;
if(ctrlName == #"Studio"){
newVC = [[StudioView alloc] initWithNibName:#"StudioView" bundle:nil];
}
else if(ctrlName == #"Menu"){
newVC = [[MenuView alloc] initWithNibName:#"MenuView" bundle:nil];
}
self.curVC = newVC;
[UIView transitionWithView:self.window
duration:1.0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
newVC.view.transform = CGAffineTransformConcat(newVC.view.transform, CGAffineTransformMakeTranslation(-1024, 0));
[self.rootVC.view addSubview:newVC.view];
newVC.view.transform = CGAffineTransformConcat(newVC.view.transform, CGAffineTransformMakeTranslation(1024, 0));
oldVC.view.transform = CGAffineTransformConcat(oldVC.view.transform, CGAffineTransformMakeTranslation(1024, 0));
}
completion:^(BOOL finished){
if(finished){
[oldVC release];
}
}
];
}
And I switch views in my UIViewController as follow:
AppDelegate *ad = (AppDelegate*)[[UIApplication sharedApplication] delegate];
[ad changeRootController:#"Studio"];
newVC isn't released.
The block should retain the newVc so after your transitionWithView
you should call. (last line of function)
[newVC autorelease];
Thats assuming that the self.curVC property is strong OR retained

Resources