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 :)
Related
I'm trying to display a full image on screen, by pushing a modal view, with the full image, i managed to do that with no problem, but for some reason i cannot hide the status bar on the modal, i'm presenting the modal from a didSelectItemAtIndexPath of a collection view, i'm trying to hide the status bar, before calling the presentViewController, here's the code:
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSArray *infoPhoto = self.imagesFromCD[indexPath.row];
// NSLog(#"Info photos = %#", infoPhoto);
NSString *imageName = [[self.imagesFromCD valueForKey:#"imgNameCD"]objectAtIndex:indexPath.row];
UIImage *imageToPass = [self getImageFromDocuments:imageName];
displayImageViewController *displayVC = [[displayImageViewController alloc]init];
displayVC.modalPresentationStyle = UIModalPresentationCustom;
displayVC.transitioningDelegate = self;
displayVC.foto = infoPhoto;
displayVC.imageToDisplay = imageToPass;
UIApplication *myapp = [UIApplication sharedApplication];
[myapp setStatusBarHidden:YES withAnimation:YES]; // Heres where the bar should be hidden.
[self presentViewController:displayVC animated:YES completion:nil];
}
I also tried to add the:
-(BOOL)prefersStatusBarHidden {
return YES;
}
Inside the Modal .m file, but nothing happened.
First of all set in your info.plist View controller-based status bar appearance is equal to no and than use below where ever you want to status bar hidden or not:
[[UIApplication sharedApplication] setStatusBarHidden:YES
withAnimation:UIStatusBarAnimationFade];
[[UIApplication sharedApplication] setStatusBarHidden:NO
withAnimation:UIStatusBarAnimationFade];
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
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.
Has anyone ever encountered an issue where a navigation bar with custom background is shifted to the top when the screen is transitioning between a hidden status bar and a shown status bar?
The problem is this issue doesn't happen with a debug build, but it does happen with a release build. I'm really confused because I'm not using any conditionals for UI behaviors.
Additionally, this will only happen if the app is entering a foreground mode in a "fullscreen" state. Then I switched from a fullscreen state to a non-fullscreen state, the problem occurs.
Update: this issue occurs regardless of whether I'm using a custom background or not.
I'm using iOS 4.3 SDK running on iOS 4.3.3.
I do this transition like this:
UIWindow *window = [[UIApplication sharedApplication] firstWindow];
[window addMoveInTransitionWithDuration:0.5 subtype:kCATransitionFromBottom];
[self.fullScreenViewController.view removeFromSuperview];
[self presentNonFullScreenViewAnimated:NO];
This is the firstWindow method:
- (UIWindow *)firstWindow
{
if ([self.windows count] > 0)
return [[self windows] objectAtIndex:0];
return [self keyWindow];
}
This is the presentNonFullScreenViewAnimated: method
- (void)presentNonFullScreenViewAnimated:(BOOL)animated
{
[[UIApplication sharedApplication] setStatusBarHidden:NO];
[self.navigationController setNavigationBarHidden:NO animated:NO];
NonFullScreenViewController *viewController = [[NonFullScreenViewController alloc] init];
[self.navigationController pushViewController:viewController animated:animated];
[viewController release];
}
I have two simple UIViewControllers, their views are 320 x 460 with status bars. I do in AppDelegate
self.window.rootViewController = [[[SimpleController alloc] init] autorelease];
[self.window makeKeyAndVisible];
In SimpleController I have a button that does
- (IBAction) switchToVerySimpleController
{
[UIView transitionWithView: [[UIApplication sharedApplication] keyWindow]
duration: 0.5
options: UIViewAnimationOptionTransitionFlipFromLeft
animations:^{ [[UIApplication sharedApplication] keyWindow].rootViewController = [[[VerySimpleController alloc] init] autorelease]; }
completion: NULL];
}
The new view (VerySimpleController.view) is filled with a blue color. After animation new view is shown with a tiny white stripe (with the size of a status bar) at the bottom and then it jumps down into place. Why is it happening and how to avoid that? I suppose its status bar to blame, and I tried to set statusBar = Unspecified in IB for both views, but it doesn't help.
UPDATE:
When I hide statusBar (thru setting in .info file) from the start, no view adjustment occurs. But still... I need to show statusBar and I need that animation working properly.
When a rootViewController is assigned to a window, a new frame is assigned to the rootViewController's view if a status bar is present. This is so that the rootViewController's
view won't be hidden under the status bar.
Since you're setting the window's rootViewController inside the animation block, the new frame assignment gets animated as well.
To not show the jump you might set the frame of the rootViewController's view before the animation with something like this:
- (IBAction) switchToVerySimpleController
{
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
VerySimpleController *vsc = [[[VerySimpleController alloc] init] autorelease];
vsc.view.frame = CGRectMake(vsc.frame.origin.x,
statusBarFrame.size.height,
vsc.frame.size.width,
vsc.frame.size.height);
[UIView transitionWithView: [[UIApplication sharedApplication] keyWindow]
duration: 0.5
options: UIViewAnimationOptionTransitionFlipFromLeft
animations:^{ [[UIApplication sharedApplication] keyWindow].rootViewController = vsc }
completion: NULL];
}
It seems that this issue still sometimes happen and it's probably a bug.
To avoid this 'jump' add this code to the viewWillAppear method of the view controller which needs to be shown:
swift
navigationController?.navigationBar.layer.removeAllAnimations()
objective-c
[self.navigationController.navigationBar.layer removeAllAnimations];
The transition will now finish without the 'jump'.