iOS scale UIView with UINavigationBar and UIStatusBar - ios

I need to implement scrollview, which contains few scaled subviews with UINavigationBar and UIStatusBar.
How to get UIStatusBar for display it on scaled view? Because now I implemented this (shown on the left — scaled view without status bar) but I need this (shown on the right):
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Storyboard" bundle:nil];
//get view controller and navigation controller from storyboard
UINavigationController *mainNavigControll = [sb instantiateViewControllerWithIdentifier:#"mainNavigControll"];
UIViewController *myViewObject = [sb instantiateViewControllerWithIdentifier:#"myViewController"];
//scaled view and all sub view
CGAffineTransform transform = CGAffineTransformMakeScale(scale, scale);
for( UIView* v in myViewObject.view.subviews )
v.transform = transform;
[myViewObject.view addSubview:myViewObject.navigationController.view];
myViewObject.view.transform = transform;
//get navigation bar and set navigation item
UINavigationBar * navig_bar = mainNavigControll.navigationBar;
[navig_bar pushNavigationItem:myViewObject.navigationItem animated:NO];
//add navigation bar to view
[myViewObject.view addSubview:navig_bar];
//TODO: need added UIStatusBar ????
...
//add to scroll view
[_scrollView addSubview:myViewObject.view ];
This scrollview must looks like multitasking on iOS 7, but only with some internal views.

Use [[UIApplication sharedApplication] setStatusBarHidden:NO]; in custom view controller you have.

Related

Unable to click "under" a hidden TabBar

I hide my tab bar like so:
self.tabBarController.tabBar.hidden = YES;
And because now there is a black bar where it once stood I stretch the view which is a UIWebView on top(or is it under?) that empty space. The UIWebView is in a UIViewController. I do that with a constraint which by default is like so:
The code for the constraint:
if(self.tabBarController.tabBar.hidden){
self.webviewBottomConstrain.constant = -self.tabBarController.tabBar.frame.size.height;
}else{
self.webviewBottomConstrain.constant = 0;
}
However if I tap the device on the place where the TabBar was it will not execute. It is as if there is something invisible there with the size of the tab bar. I have also tried hiding it the way this thread sugests. Still the same result.
Update: It seems that when you tap on the invisible tab bar the tap is recognized by the tab bar and not by the view that is visible under the tab bar
self.extendedLayoutIncludesOpaqueBars = YES;
this will solve you problem
You hide your tabBar by setting its hidden property to NO? Try setting it to YES. Unless I am misunderstanding what you are trying to do, it seems like your tab bar is not hidden with that code.
Another thing I would check is to see if User Interaction Enabled is checked for the web view. If it is not, that can seem like there is something invisible blocking you from interacting with your view.
Well I am using quite ugly hack to fix this. I am hiding the tab bar in another way now:
if (shouldShow) {
self.hidesBottomBarWhenPushed = NO;
UIViewController *someView = [[UIViewController alloc] init];
[self.navigationController pushViewController:someView animated:NO];
[self.navigationController popToViewController:self animated:NO];
} else if (shouldHide) {
self.hidesBottomBarWhenPushed = YES;
self.tabBarController.hidesBottomBarWhenPushed = YES;
self.navigationController.hidesBottomBarWhenPushed = YES;
UIViewController *someView = [[UIViewController alloc] init];
[self.navigationController pushViewController:someView animated:NO];
[self.navigationController popToViewController:self animated:NO];
}
I do need that random view because I cannot push the view on itself.
I had the same issue when hiding the tab bar by moving it offscreen to the bottom. My custom UITabBarViewController was intercepting the touch events in the area vacated by the tab bar, so instead of changing the frame of the tab bar to move the tab bar offscreen, I extended the height of my tab bar view controller so that the tab bar still moved offscreen, but the child view above the tab bar now filled that space. This allowed the touches to be received by the child view.
As you may see with view hierarchy instrument, UITabBar is not directly blocking your tap, but your current view controller's view height is not full screen:
So, the tap doesn't response because your finger's y position is higher than view's maxY.
Code like this (inside your UITabBarController) will expand your view's height, according to tabbar visibility, and all tap events will work correctly.
func updateTabBarAppearanceWithDegree(_ degree: CGFloat) {
let screenHeight = UIScreen.main.bounds.size.height
let tabBarHeight = self.tabBar.frame.size.height
self.tabBar.frame.origin.y = screenHeight - tabBarHeight * degree
self.tabBar.alpha = degree
let currentNavigation = self.selectedViewController as? UINavigationController
if let currentTopView = currentNavigation?.viewControllers.last?.view {
currentTopView.frame.size.height = self.tabBar.frame.origin.y
}
}

iOS7 slideout drawer draggable bug

I am trying to implement a slideout drawer similar to a the one found in this guide: http://www.raywenderlich.com/32054/how-to-create-a-slide-out-navigation-like-facebook-and-path
I have two subviews that are added to the navigation controller, The drawer is initialized as follows in viewDidLoad:
self.drawerViewController = [[DrawerViewController alloc] initWithNibName:#"drawer" bundle:nil];
self.drawerViewController.view.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.drawerViewController.view];
[self addChildViewController: self.drawerViewController];
[self.drawerViewController didMoveToParentViewController:self];
self.drawerViewController.view.frame = CGRectMake(0, 0, 150, self.view.frame.size.height);
then the contentview is initialized using a viewcontroller from my storyboard (and i call send subviewtoback to move the drawer behind it):
UIStoryboard* sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.contentViewController = [sb instantiateViewControllerWithIdentifier:#"HomeViewController"];
[self.view sendSubviewToBack:self.drawerViewController.view];
[self pushViewController:self.contentViewController animated:YES];
I move the main content view by animating the frame of the contentview which uncovers the drawer underneath:
[UIView animateWithDuration:SLIDE_TIME delay:0 options:UIViewAnimationOptionBeginFromCurrentState
animations:^{self.contentViewController.view.frame = CGRectMake(150, 0, self.view.frame.size.width, self.view.frame.size.height);
}completion:nil];
Which works but if I do something like click the margin of the drawer and drag, the drawer can end up covering the entire screen in the iphone simulator or disappearing showing the black background (which is more easily reproduced when rotating the device while showing drawer). My question is why is the drawerview draggable and how do you prevent this?
Edit:
I have found the source of the dragging is from this addChildViewController line:
[self addChildViewController: self.drawerViewController];
However removing this doesnt allow users to click the table cells anymore.
The problem was using a navigation controller as a container of subviews. I don't think it's meant to be used this way so I ended up scrapping this and rewriting it with a uiviewcontroller container instead.

Add a UINavigationController nested inside a container view controller to a UITabBarController

I have a UIViewController (red) set as the first tab of a UITabBarController as shown in the storyboard below. This view controller is a container view controller and loads a UINavigationController inside its contentView (the white rectangle inside the red view controller).
This is my code for loading the navigation controller inside the red view controller's contentView:
- (void)viewDidLoad
{
[super viewDidLoad];
// instantiate navigation controller
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UINavigationController *navigationVC = [storyboard instantiateViewControllerWithIdentifier:#"N"];
// place navigation controller inside content view
[self addChildViewController:navigationVC];
navigationVC.view.frame = self.containerView.bounds;
[self.containerView addSubview:navigationVC.view];
[navigationVC didMoveToParentViewController:self];
}
From what I know about view controller containment this should work as I am explicitly setting the frame for the navigation controller. However, when there are enough cells in the tableView to exceed the container's height there is always a bar at the end of the tableView when I scroll down. I have set the tableView's backgroundColor to orange and the cell's backgroundColor to white in order to see the difference.
How do I get rid of that orange gap at the end of the tableView?
(Note: I am not using autolayout and I need a solution that works for both - iOS7 and iOS6.)
I know you are also looking for an answer which works on iOS 6, but on iOS 7 and above you can use
self.extendedLayoutIncludesOpaqueBars = YES;
Have you tried setting self.edgesForExtendedLayout = UIRectEdgeAll; in -(void)viewDidLoad of Table View Controller - Root?
Note: iOS 7 only

Custom view controller presentation causes the navigation bar to bounce

I'm presenting a view controller using the transitioning delegate modally from my root view controller.
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
UIViewController *rootVC = [window rootViewController];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:authVC];
navController.modalPresentationStyle = UIModalPresentationCustom;
navController.navigationBar.translucent = NO;
navController.transitioningDelegate = self;
[rootVC presentViewController:navController animated:YES completion:nil];
My transitioning delegate adds the view as follows, where authorizationVC is the login view pictured in the screenshots.
UIView *containerView = [transitionContext containerView];
[containerView addSubview:blurredView];
[containerView insertSubview:_authorizationVC.view aboveSubview:blurredView];
_authorizationVC.view.frame = CGRectMake(10, 30, 300, 450);
At first, the view animates in, and the navigation bar is full height, what I believe to be 64 pixels (44 for the nav bar and 20 for the status bar).
As soon as my animation completes, the nav bar shrinks to 44 pixels. The transition is jarring. The content inside my view controller is unaffected.
How do I avoid this jittering navigation bar? The second image is what I'd like to achieve.
Set all the properties of the view before adding it to its superview.
UIView *containerView = [transitionContext containerView];
_authorizationVC.view.frame = CGRectMake(10, 30, 300, 450); /// Change the frame FIRST!
[containerView addSubview:blurredView];
[containerView insertSubview:_authorizationVC.view aboveSubview:blurredView];
Voila! The nav bar acts as expected.
I would avoid using a UINavigationController if you don't really need it.
The UINavigationController takes into account the topLayoutGuide in the way it sizes the navigation bar. If you just want the coloured bar and close button, I'd simplify it and use your own views for that.
If you must use a UINavigationController you could try playing with the status bar's appearance and see how it affects the navigation controller's presentation.

iOS - Semi-transparent modal view controller

I want to present a view controller with a slightly transparent background modally over the current view, such that the first view is slightly visible under the modal view.
I set the alpha value of the modal view controller and set the modalPresentationStyle to UIModalPresentationCurrentContext, as suggested in another post.
The result is that the view background is transparent when animating up, but when view controller is in place it changes to opaque black. It goes back to being transparent while animating the dismissal.
How can I get it to be transparent when active ?
I have tested in iOS 6 and 7. The code I am using follows:
MyModalViewController *viewController = [[MyModalViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
[navController setNavigationBarHidden:YES];
self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
[self.navigationController presentViewController:navController animated:YES completion:NULL];
iOS 8 added a new modal presentation style specifically for this purpose:
presentedViewController.modalPresentationStyle = UIModalPresentationOverFullScreen
From the spec:
UIModalPresentationOverFullScreen
A view presentation style in which the presented view covers the screen. The views beneath the presented content are not removed from the view hierarchy when the presentation finishes. So if the presented view controller does not fill the screen with opaque content, the underlying content shows through.
If you are targeting ios 8 and above you can set the modal presentation style to "over current context" and you are done.
If ios 7 and below, you would have to create a custom transition style so that the presenting screen doesn't go blank after transition. That is rather complicated.
The solution I present offers a lot of flexibility: make a screenshot before showing the modal dialog and set that as the background image for the application window. By default, that background is black (that is what you see when the back view controller dissapears). Change the background to the screenshot of the app. Make the screenshot in the viewWillAppear or viewDidLoad method of your transparent view. This works even with push segues, not only modal dialogs, but you should avoid animations. In general, avoid animations which affect the position of the background view because those will make it seem like it snaps back into place when transition finishes. It is a good idea to reset the background to its previous black image on viewDidDissapear to avoid unwanted effects.
You can maintain a stack of such background images and you can do multiple "transparent" push seques. Or have some complex/deep menu which appears on top of some main screen. For these many reasons I think this solution is better than rolling your own transitioning code. It is more flexible and easier to implement, and you don't have to deal with the animations yourself.
The reason that the BG view controllers disappear after a modal is shown is that the default transition in iOS 7 removes the BG view after animation completed. If you define your own transition and you set your BG view not to be removed (just changing its alpha) then you will have the transparent modal view.
Same problem occured to me. I have solved it by looking at the following url about a custom alert controller. I managed to get it working even with a UINavigationController.
Swift
let viewController = UIViewController()
viewController.providesPresentationContextTransitionStyle = true
viewController.definesPresentationContext = true
viewController.modalPresentationStyle = .overCurrentContext
viewController.modalTransitionStyle = .crossDissolve
DispatchQueue.main.async {
self.navigationController?.present(viewController, animated: true, completion: nil)
}
Objective C
UIViewController *viewController = [UIViewController new];
viewController.providesPresentationContextTransitionStyle = true;
viewController.definesPresentationContext = true;
viewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
viewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
dispatch_async(dispatch_get_main_queue(), ^{
[self.navigationController presentViewController:viewController animated:true completion:nil];
});
Here is a solution.
Create your presenting view controller. Add a backView to this view controller's main view. Name this as backView.
In SecondViewController.m
-(void)viewDidLoad
{
// Make the main view's background clear, the second view's background transparent.
self.view.backgroundColor = [UIColor clearColor];
UIView* backView = [[UIView alloc] initWithFrame:self.view.frame];
backView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
[self.view addSubview:backView];
}
Now you have a view controller with half transparent background. You can add anything you want to the self.view , the rest will be half transparent.
After that, in FirstViewController.m
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:secondViewController animated:YES completion:nil];
My solution is this:
Create a custom transparent overlay UIView that comes over any view, navigationbar and tabbbar.
-In the navigation controller (or tabbar controller) that your view controller is embedded in I create a custom view with it's frame equal to the frame of the navigation controller's view.
-Then I set it offscreen by setting it's origin.y to navigationController.view.height
-Then I create 2 functions -(void)showOverlay and -(void)hideOverlay that animate the overlay view on and off screen:
- (void)hideOverlay{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
CGRect frm = self.helpView.frame;//helpView is my overlay
frm.origin.y = self.offscreenOffset; //this is an Y offscreen usually self.view.height
self.helpView.frame = frm;
[UIView commitAnimations];
}
- (void)showOverlay{
[self.view bringSubviewToFront:self.helpView];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
CGRect frm = self.helpView.frame;
frm.origin.y = self.onscreenOffset;
self.helpView.frame = frm;
[UIView commitAnimations];
}
-In my view controller I can just call
[(MyCustomNavCtrl *)self.navigationController showOverlay];
[(MyCustomNavCtrl *)self.navigationController hideOverlay];
And that's about it.
FYI: The syntax is now:
childVC.modalPresentationStyle = UIModalPresentationStyle.OverFullScreen
Why don't you try setting this in AppDelegate
self.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
then changing the alpha on the view being presented

Resources