The current rootViewController of window in my app is MainViewController. and there's a button in another view controller called SubViewController, I want to show UISplitViewController if a user click the button. I have implemented it as following:
//SubViewController.m
UISplitViewController *splitVC =[self splitVC];
self.view.window.rootViewController = splitVC;
there's no animation to show splitVC, I need to show it with slide style, example, to slide the SubViewController.view to right to show the UISplitViewController, and if the user click a button on UISplitViewController, to slide back the SubViewController.view
Try it this way:
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
UISplitViewController *splitVC =[self splitVC];
[UIView transitionWithView:self.view.window
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{
appDelegate.window.rootViewController = splitVC;
}
completion:^(BOOL finished){
}];
You can specify different animation types with the options parameter
Related
What i want to achieve is: after tapping a small view with some data i want to make it full screen and possibly make it to be a new vc.
For now I animate uiview to full screen with great success, but whole logic of this view is in it's "parent".
Is it possible to animate viewcontroller out of the uiview which is similar (for. eg. like in LayoutTransitions in Android SDK)?
Sample code of my uiview to full screen using autolayout:
sender.view.transform = CGAffineTransformIdentity;
[UIView animateWithDuration:0.2
animations:^{
sender.view.frame = self.view.window.bounds;
} completion:^(BOOL finished) {
[((CSTicketView*)sender.view) showMenu];
}];
[[UIApplication sharedApplication]
setStatusBarHidden:YES
withAnimation:UIStatusBarAnimationFade];
[[self navigationController] setNavigationBarHidden:YES animated:YES];
Let's move your sender view to Window as like below,
AppDelegate * appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
[appDelegate.window addSubview:sender.view];
[UIView animateWithDuration:0.2
animations:^{
sender.view.frame = self.view.window.bounds;
} completion:^(BOOL finished) {
[((CSTicketView*)sender.view) showMenu];
}];
Absolutely possible.
You can use the new view controller transitions model in iOS7.
I would definitely recommend a few resources to check on top of my basic explanation:
this
and this
I have some sample code for a demonstrator of this here
Ultimately you make a new view controller for the view you are transitioning to, and you also make an NSObject subclass that conforms to UIViewControllerAnimatedTransitioning which contains the code to transition between them. Sounds complex but if you watch the video I linked to and read the other reference it'll make total sense.
I have a login view that checks to see if there are default settings, then syncs data. If there are no default settings, the view waits for the user to login. if there are settings and the data syncs correctly, it should switch to my split view.
The code works if the user enters their login information. It syncs the data, then switches the view. If the user is already logged in, it hits the function and doesnt switch the view.
Here is the code being called by both paths:
-(void)redirect{
NSLog(#"Redirect#");
UISplitViewController *split = [self.storyboard instantiateViewControllerWithIdentifier:#"orders_split"];
[self.view.window setRootViewController:split];
}
"Redirect#" shows in the log on the initial load if the user has already logged in once. I have confirmed that there are no sync errors, it hits the function but does not perform the switch.
I am moving from a standard view with nav controller to a splitview, so I cannot use a manual segue trigger.
try to use app delegate:
UISplitViewController *split = [self.storyboard instantiateViewControllerWithIdentifier:#"orders_split"];
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.window.rootViewController = split;
in my projects I do it with animation:
+(void)setRootController:(UIViewController*)controller
storyboard:(UIStoryboard*)storyboard{
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[UIView
transitionWithView:appDelegate.window
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^(void) {
BOOL oldState = [UIView areAnimationsEnabled];
[UIView setAnimationsEnabled:NO];
appDelegate.window.rootViewController = controller;
[UIView setAnimationsEnabled:oldState];
}
completion:nil];
}
I am integrating Pushwoosh SDK for Push Notification, which is using UIWindow to represent HTML page sent from Pushwoosh portal
- (void) showWebView {
self.richPushWindow.alpha = 0.0f;
self.richPushWindow.windowLevel = UIWindowLevelStatusBar + 1.0f;
self.richPushWindow.hidden = NO;
self.richPushWindow.transform = CGAffineTransformMakeScale(0.01, 0.01);
[UIView animateWithDuration:0.3 animations:^{
self.richPushWindow.transform = CGAffineTransformIdentity;
self.richPushWindow.alpha = 1.0f;
} completion:^(BOOL finished) {
}];
}
- (void) showPushPage:(NSString *)pageId {
NSString *url = [NSString stringWithFormat:kServiceHtmlContentFormatUrl, pageId];
HtmlWebViewController *vc = [[HtmlWebViewController alloc] initWithURLString:url];
vc.delegate = self;
vc.supportedOrientations = supportedOrientations;
self.richPushWindow.rootViewController = vc;
[vc view];
}
And on closing on HTML page it calls
self.richPushWindow.transform = CGAffineTransformIdentity;
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.richPushWindow.transform = CGAffineTransformMakeScale(0.01, 0.01);
self.richPushWindow.alpha = 0.0f;
} completion:^(BOOL finished) {
AppDelegate * appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
self.richPushWindow.hidden = YES;
}];
Now I want to call my view controller on closing of this HTML page. So I tried to present myviewcotrlller in this block completion but not presenting.
Actually here problem is that there are two UIWindows in my app one of app and other used by sdk. Now if i try to present view controller from this html page which is on separate UIWindow so it creates a separate hierarchy and when i close this window also removes my presented viewconroller due to parent-child relationship. And if do not close this window then how to come back to actual flow of app.
I want that new controller should be presented from that new window and after that window should be close and flow of app should not be affected by additional window. Is it possible? If my concept is wrong, Please help if anyone has idea
Edit: second uiwindow never be key window, it only becomes visible by setting higher windowlevel and become hidden
The problem is that right after this completion block richPushWindow will be gone, effectively this means you are trying to present view controller on a hidden window.
The solution is very simple. Use main window to present view controller. Some pseudocode:
Add view from the ViewContoller to the main window subviews:
[appDelegate.window addSubview:myViewController.view];
Modal:
[appDelegate.window.rootViewController presentModalViewController:myViewController]
Using View Controller hierarchy:
Push your viewController to the main viewController stack. For example if you have navigationController, just push it there.
I hope it helps!
I'm looking for the name of the class Apple uses to present a number of Images in full screen (similar to the AppStore-App on iPad when you tap the preview images of any App. In the bottom of the view is a bar with little preview Images from all the Images).
If this is a public class, how is it called and is it available for iPhone as well?
Ok so I have created my own ImageFullScreenPresenter.
What is important for anybody trying to build their own ImageFullScreenPresenter is to make it a subclass of UIViewController.
PKImageFullScreenPresenter *pkImageFullScreen = [[[PKImageFullScreenPresenter alloc] initWithNibName:#"PKImageFullScreenPresenter" bundle:nil imageArray:myImageArray] autorelease];
AppDelegate *appDel = (AppDelegate *)[UIApplication sharedApplication].delegate;
UIViewController *rootViewController;
if (DEVICE_IS_IPAD) {
//since the splitviewcontroller is the rootviewcontroller on ipad i set it as my temporary rootViewcontroller for ipad
rootViewController = appDel.splitViewController;
}
if (DEVICE_IS_IPHONE) {
//on iphone i need the tabbarcontroller as temporary rootviewcontroller
rootViewController = appDel.tabBarController;
}
//set the alpha to zero, so it can fade in animated
pkImageFullScreen.view.alpha = 0;
//save the temporary rootViewController, so I can set it back when dissmissing the ImageViewController
pkImageFullScreen.superViewController = rootViewController;
//hide the status bar
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
//setting black backgroundcolor
[UIApplication sharedApplication].keyWindow.backgroundColor = [UIColor blackColor];
//init the fullscreencontroller as rootview
[[UIApplication sharedApplication].keyWindow setRootViewController:[[[UINavigationController alloc] initWithRootViewController:pkImageFullScreen] autorelease]];
//smooth fade animation
[UIView animateWithDuration:.5f
animations:^(void){
pkImageFullScreen.view.alpha = 1;
}];
Doing so, allows me to present the ImageFullScreenPresenter on iPhone and iPad, no matter you are using a window-based app, a splitViewController on iPad or whatever.
When dismissing the ImageFullScreenPresenter i set the temporary saved rootViewController back with an animation:
- (void)closeView:(id)sender{
[UIView animateWithDuration:.5f
animations:^(void){
self.view.alpha = 0;
}completion:^(BOOL finished){
//show the statusbar again
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
//setting the statusbarstyle
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent];
//set the backgroundcolor for the window
[UIApplication sharedApplication].keyWindow.backgroundColor = GLOBAL_TINT_COLOR; //my custom color vor all GUI Objects
//set the temporary rootViewController back
[[UIApplication sharedApplication].keyWindow setRootViewController:superViewController];
//sometimes the navigationbar hides the statusbar, the following two lines help me out
[[UIApplication sharedApplication].keyWindow.rootViewController.navigationController setNavigationBarHidden:YES];
[[UIApplication sharedApplication].keyWindow.rootViewController.navigationController setNavigationBarHidden:NO];
}];
}
I dont know if this is the right way to go, but it works perfectly finefor me. I do not have to worry abput any rotation issues like I would have when i directly add this to [UIApplication sharedApplication].keyWindow.
I hope this helps others who try do achieve the same :)
I have a view controller which is not fullscreen (has a status bar) and want to present a modal view controller which is fullscreen.
If I hide the status bar at the beginning of the animation (parent's viewWillDisappear or modal's viewWillAppear) then for a moment the parent will be visible without a status bar, looking like a bug.
If I do it at the end of the animation (parent's viewDidDisappear or modal's viewDidAppear) then the status bar will be visible for a moment over the modal view, i.e. it won't appear as the modal view "covered it".
Is there a way to do this nicely?
edit:
One possibility would be to create a UIWindow with windowLevel=alert for at least the duration of the animation. The sample iAd ad seems to cover the status bar nicely without another window, so it must be possible somehow.
Another fun little project. This was the best I could come up with. It's not too bad if you don't mind using your own container controller to manage presenting/dismissing view controllers. I try to do things in a general way but this could be rolled into an app w/ the ContainerViewController if desired.
Note that I only implemented the equivalent of UIModalTransitionStyleCoverVertical. You can customize the animation however you like as well.
Relevant animation code:
- (void)presentViewController:(UIViewController *)viewControllerToPresent
{
// do nothing if no controller
if (!viewControllerToPresent) return;
[__viewControllers addObject:viewControllerToPresent];
CGRect toFrame = viewControllerToPresent.view.frame;
toFrame.origin = CGPointMake(0, CGRectGetMaxY(self.view.bounds));
viewControllerToPresent.view.frame = toFrame;
[UIView transitionWithView:self.view
duration:0.2
options:UIViewAnimationOptionTransitionNone
animations:^{
[[UIApplication sharedApplication] setStatusBarHidden:viewControllerToPresent.wantsFullScreenLayout withAnimation:UIStatusBarAnimationSlide];
[self.view addSubview:viewControllerToPresent.view];
viewControllerToPresent.view.frame = [UIScreen mainScreen].applicationFrame;
}
completion:nil];
}
- (void)dismissViewController
{
// nothing to dismiss if showing first controller
if (__viewControllers.count <= 1) return;
UIViewController *currentViewController = [__viewControllers lastObject];
UIViewController *previousViewController = [__viewControllers objectAtIndex:__viewControllers.count - 2];
[UIView transitionWithView:self.view
duration:0.2
options:UIViewAnimationOptionTransitionNone
animations:^{
[[UIApplication sharedApplication] setStatusBarHidden:previousViewController.wantsFullScreenLayout withAnimation:UIStatusBarAnimationSlide];
CGRect toFrame = currentViewController.view.frame;
toFrame.origin = CGPointMake(0, CGRectGetMaxY(self.view.bounds));
currentViewController.view.frame = toFrame;
}
completion:^(BOOL finished) {
[currentViewController.view removeFromSuperview];
[__viewControllers removeLastObject];
}];
}
I do that in my app with this code:
[[UIApplication sharedApplication] setStatusBarStyle: UIStatusBarStyleBlackOpaque];
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation: UIStatusBarAnimationSlide ];
DocumentListViewController * dl = [[DocumentListViewController alloc] initWithNibName:#"DocumentListView" bundle:nil] ;
UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:dl];
[dl release];
// Go to the list of documents...
[[self.view superview] addSubview:nav.view];
nav.view.alpha = 0.0 ;
[self hideActivityAlert];
[UIView animateWithDuration:1.0 animations:^{
nav.view.alpha = 1.0; } completion:^(BOOL A){
[self.view removeFromSuperview];
[self release];} ];
The status bar is presented shoftly while the animation occurs.
You have to be sure that the first view, when status bar is going hidden will fill the space. Use the property autoresizingMask with proper value.
Here's a solution that seems to work. You can derive the viewcontroller you want to present modally from my TSFullScreenModalViewController, or you can just implement the code right in the view controller itself.
#interface TSFullScreenModalViewController : UIViewController
{
UIWindow* _window;
}
- (void) presentFullScreenModal;
#end
#implementation TSFullScreenModalViewController
- (void) viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear: YES];
[_window resignKeyWindow];
[_window release];
_window = nil;
}
- (void) presentFullScreenModal
{
UIViewController* rvc = [[UIViewController new] autorelease];
rvc.view.backgroundColor = [UIColor clearColor];
_window = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds] ;
_window.windowLevel = UIWindowLevelStatusBar+1;
_window.backgroundColor = [UIColor clearColor];
_window.rootViewController = rvc;
[_window makeKeyAndVisible];
[UIApplication sharedApplication].statusBarHidden = YES;
[rvc presentModalViewController: self animated: YES];
[UIApplication sharedApplication].statusBarHidden = NO;
}
#end
Derive your modal view controller, like this:
#interface MyModalViewController : TSFullScreenModalViewController
{
}
- (IBAction) onDismiss:(id)sender;
#end
Use it from another view controller, like this:
- (IBAction) onShowModal:(id)sender
{
MyModalViewController* mmvc = [[MyModalViewController new] autorelease];
[mmvc presentFullScreenModal];
}
Finally, dismiss your view controller as you normally would:
- (IBAction) onDismiss:(id)sender
{
[self dismissModalViewControllerAnimated: YES];
}
Might be a bit of a hack but have you considered:
Take a screenshot programatically of the first view with the status bar (see this SO question)
Create a new view which displays the image you just took in fullscreen (using UIImage's initWithFrame)
Hide the status bar
Present the modal view controller
Then to dismiss the modal view, just reverse the steps.
EDIT:
Won't work for this because you can't take screenshots of the status bar.
It could be as simple as delaying the presentation of your modalViewController using performSelector:withDelay:
Tell the status bar to animate out and then launch the modal controller with the right delay so it coincides with the status bar animation.