How can I add a transparent view? - ios

I want to push a view controller onto the navigation stack but I don't want its view to initially appear - in other words I want the view that was visible when the view controller is push to still be visible.
I tried setting the view controller's view's alpha value to 0.0 which I thought would make it transparent. But instead what is happening is that when I push the view controller on the the stack the screen is white. If I set the alpha to 1.0 then the view controller's view appears as expected.
Why is it white and not transparent?

you will have to add the view to the viewcontrollers manually
Not pushing it
For example do the following
YourViewController *vc = [[YourViewController alloc] init];
[self.view addSubview:vc.view];
vc.view.alpha = 0.0;
//Animate Here
vc.view.alpha = 1.0;
//Commit Animate Here
Please not that you will have to do some additional coding to implement the release of the vc, since now you have retained vc.view you will not be able to release vc easily,
Another solution is instead of implementing the second view as a viewcontoller implement it as uiview, and the xib class will be view and not uiviewcontroller

Maybe make sure that the opaque property is set to NO?
Or perhaps the view you're pushing on was built in interface builder, and you have a background color of white with another view you put on top of it and you only changed the opacity of the subview?

Related

UIView background color changing when view controller finishes loading

I'm loading a view controller modally via another view controller and I'm trying to change the background color using:
override func viewDidLoad() {
super.viewDidLoad()
transparentBG.backgroundColor? = UIColor.black.withAlphaComponent(0.4)
// transparentBG is a UIView defined in storyboard
}
While the view is animating into position (sliding up) it maintains the alpha value I set. But once it reaches the top of the screen it removes the alpha component and is changing the color to what looks like the color with the alpha component, so like a gray color, but with no transparency as seen in the image below.
Is there anyway to maintain the alpha component after if finishes loading?
Step one: Change this to an overFullScreen presentation.
Step two: There is no step two.
just set presentaion style on viewContriller
[myViewcontroller setModalPresentationStyle:UIModalPresentationCustom];
[myViewcontroller setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[self.navigationController presentViewController:myViewcontroller animated:true completion:nil];
What is happening is that the alpha is being kept, but the previous view is being removed once the animation is complete.
There are a couple approaches you can take.
Take a screen shot of the previous view and insert that as a background in the new view. Look at the drawViewHierarchyInRect function. You can grab the screen shot in the new view controller's init method, then set it as a background image in the viewDidLoad.
The other approach would be to add the overlay as a subview, either to the existing view, or even the window itself.
I've used both methods successfully.

Popping UIViewController causes previous UIViewControllers View to change position

I have a UINavigationController with a UIViewController set as it's rootController, it contains a background on its UIView using an image set just under the navBar. I then push onto the navigation controller a new UIViewController and when the back button is pushed, the previous controller looks different. Using the visual debugger I can see that the self.view has moved entirely down below the navBar where previously it was at the top. I have no idea and been racking my brains as to why this might be happening
-(void)pushIPhoneMessagingContactsController:(MessageContactsViewController *)contactsController{
self.selectorView.hidden = YES;
[self.navigationController pushViewController:contactsController animated:YES];
}
On the RootViewController (iPhoneMessagingNotificationsController)
-(void)viewWillAppear:(BOOL)animated{
self.selectorView.hidden = NO;
[[[self navigationItem] leftBarButtonItem] setTintColor:[UIColor blackColor]];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
if ([_displayType intValue] == MESSAGES_SHOWING) {
[self.notificationsViewController.view removeFromSuperview];
[self.contentView addSubview:_messagesViewController.view];
} else {
[self.messagesViewController.view removeFromSuperview];
[self.contentView addSubview:_notificationsViewController.view];
}
}
It seems the offending line was in the viewWillAppear method of the pushed UIViewController
self.navigationController.navigationBar.translucent = YES;
Somewhere else this navigationBar gets set as translucent:
[self.navigationController.navigationBar setBackgroundImage:[UIImage new]
forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = [UIImage new];
self.navigationController.navigationBar.translucent = YES;
and to make it solid colour again:
self.navigationController.navigationBar.shadowImage = nil;
self.navigationController.navigationBar.translucent = NO;
but this code seems to mess with the layout so perhaps there is another way to change the opacity of the navBar and statusBar without affecting the layout?
What you're currently trying to do is hide or show a selectorView which really only should appear for one specific view controller.
Here's an encapsulated way to solve this that makes your selectorView a part of the root view controller, removing the connection from other view controllers. They no longer have to know about it or hide it.
Add your selectorView to your rootViewController's navigation bar titleView. (You can do this in code, or drop it in Storyboard and add an IBOutlet for it.)
self.navigationItem.titleView = selectorView;
Now when you push another view controller, its title will replace your rootViewController's selectorView title (view). Your other view controllers don't need to know anything about that view.
This is a good design approach in general. Anytime you have a control that should only appear on one view controller's navigation bar, you want to make it a part of that view controller's navigationItem (titleView, or left/right bar button items.) iOS will display the control when it presents that view controller, and hide the control when that view controller is no longer the top view controller in the navigation controller stack.
As for the 64-pixel height issue, it's likely related to some complexity in the rootViewController hierarchy that shouldn't be there.
In iOS 7/8, a view's content, by default, appears under a translucent navigation bar. Apple freely managed this for you, by insetting the first view of the view hierarchy.
From your code, it appears that you're trying to "hide" or "show" the (un)selected viewController's view.
Each view controller should have a view it controls. A view controller shouldn't be trying to control other view controller's views, or adding other view controller's views to its own view hierarchy.
Here's Apple's recommended way to approach this. Use a containerView in your rootViewController. The whole purpose of a container view is to encapsulate a view controller within a view. As your selectorView changes which view to show, you have your container view transition from one view controller to the other. (If you're not familiar with how to do that, check out this answer.)
Pin the containerView to the rootViewController's view, so Auto Layout can size it for you.
Your view hierarchy now looks like view -> containerView, instead of view -> hidden view of unselected view controller, shown view of selected view controller. Apple can adjust the first view's inset, and nothing gets incorrectly offset (by the height of the navigation control).
Update:
This question talks about scrollViewInsets and how they can be set on a view-controller-by-view-controller basis. If you do have a view controller, and you don't want its content to appear under a bar, uncheck that box.
But the best way to handle this is to "standardize" your UI, so it isn't varying from view to view. Either make the bar always be translucent, or not always be translucent. This makes transitions less "jarring" for the users.

Is it possible to change frame of view controller in UITabBarController so that UITabBarController view will be visible?

I have my own subclass of UITabBarViewController.
Is it possible to change frame for all embedded viewcontrollers' views so that own UITabBarViewController view will be visible partially?
On the attached image I set purple color for own tabBarController view.
I want to change frame of each selected view controller so that this purple view (UITabBarController view) will be visible.
I stumbled upon this answer looking for a solution myself, and found an okayish way to handle this: wrap your viewController inside another viewController as a childViewController.
Essentially, you would present a viewController with clear background, which has your content controller as childController with a frame you want it to have:
UIViewController *wrapperController = [UIViewController new];
wrapperController.backgroundColor = [UIColor clearColor];
[wrapperController addChildViewController:vc];
[wrapperController.view addSubview:vc.view];
vc.view.frame = CGRectMake(...);
Just make sure to pass the tabbarItem to the wrapper, and use that one instead of the child.

UINavigationController pushViewController pauses/freezes midway through

I am pushing a view controller via:
[self.navigationController pushViewController:[[UIViewController alloc] init] animated:YES];
But the animation lags/pauses a for half a second mid way through. The animation is not complete. Here's the gif;
With out more detail I can think of 2 possible problem with that.
Is there Shadow added in code to the view that will be covered by the new ViewController. If it is the case, use ShadowPath or an translucent view instead (the property Shadow is expensive while animating, been there done that)
Is the backgroundColor of new ViewController "clearColor" ? I've seen strange rendering problem with that kind of thing.
Try:
UIViewController *vc = [[UIViewController alloc] init];
vc.view.backgroundColor = [UIColor whiteColor];
[self.navigationController pushViewController:vc animated:YES];
That is the 2 possible problems I can think of the top of my head with so few detail.
Never rely on the default background color, it has change with iOS version and is not consistant across controls and can even be different if the view is created in code or from a Xib (in the same iOS version).
In app delegate, set your window's background color to white.
window?.backgroundColor = .white
Also in the the pushed view controller, set its view to white.
view.backgroundColor = .white
I experienced the same issue when programmatically embedding my view controller in a UINavigationController.
While setting the background color as suggested by VinceBurn solved the pausing, it made the entire animation white, fading in the actual content only when the animation finished.
For me the problem was solved by making sure the content was correctly sized in -viewDidLoad.

UINavigationController has extra status bar gap at top

This looked simple enough when I set it up, but I can't explain why this gap is present between the status bar and the navigation bar. Also, the contained view looks like it may be properly aligned, and it's just the nav bar that is shifted down. The gap looks like the size of the status bar, so I expect that has something to do with it, but I don't know what.
Here is the code for setting up the navigation controller:
- (void)viewDidLoad
{
[super viewDidLoad];
advancedVC = [[AdvancedSearchFormVC alloc] initWithNibName:#"AdvancedSearchForm" bundle:nil];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:advancedVC];
nav.navigationBar.tintColor = [UIColor defaultNavBarTint];
nav.navigationBar.topItem.title = NSLocalizedString(#"SearchTitle", nil);
UIBarButtonItem *searchButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(#"SearchButton", nil) style:UIBarButtonItemStylePlain target:self action:#selector(refreshPropertyList:)];
nav.navigationBar.topItem.rightBarButtonItem = searchButton;
self.view = nav.view;
}
The rootViewController uses a view from a xib file, where I have simulated the status bar, the navigation bar, and the tab bar.
The problem is indeed that the navigation controller always expects to leave room for the status bar, which is the 20 pixel gap. I searched around for a while before I found this solution which works:
//nav is assumed to be a subclass or instance of UINavigationController
nav.view.frame = CGRectOffset(nav.view.frame, 0.0, -20.0);
//you can then add the navigation's view as a subview to something else
I originally found an answer which did this offset to the navigationbar's view, but it didn't work. It works when you do it to the navigation controllers actual view.
I use this technique to add a navigation controller from another nib to an empty view of my main nib, so I can position it anywhere within the main screen as a subview. By using an empty view as a placeholder and positioning frame on my main nib, I create a separate nib and class to manage the navigation, which manages other nibs used to handle their screens. This way I can solve the classic "how do I add a banner, image, or custom views above my navigation controller" while having a navigation controller as a subview...in iOS 5 to be specific.
It's also worth mentioning that I use the app delegate to store and access all the other controllers, so they are retained by a persistant instance which I can access from any class. Create and synthesise some properties in the app delegate of all your controllers, and in viewDidLoad create instances. That way I can reference all the controllers used in my app later anywhere by adding:
//this shows how to store your navigation controllers in the app delegate
//assumes you've added 2 properties (UINavigationController*)"navController" and (UIViewController*)"rootController" in your app delegate
//...don't forget to add #import "AppDelegate.h" to the top of the file
AppDelegate *app = (AppDelegate*)[[UIApplication sharedApplication] delegate];
[app.navController pushViewController: app.rootController animated:YES];
//now apply the offset trick to remove the status gap
app.navController.view.frame = CGRectOffset(app.navController.view.frame, 0.0, -20.0);
I had the same problem before. The code I used to add UINavigationBar to UIViewController:
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:self];
[self.view addSubview:nc.view];
Solution:
Check the box "Wants Full Screen" with Attributes inspector of your UIViewController.
You can try to set the attribute Under Top Bars unchecked from Attributes section of UIViewController.
As we all know by now, the 20 pixel shift is to provide space for the Status bar on the top.
But infact, the view controllers coordinate system is kept in place and only the navigation bar frame is shifted down by 20 pixels. This makes the navigation bar to actually overlap the top 20 pixels of the view.
Logging the navigation bars frame origin, it will show (0.0, 20.0)
So the solution is to simply reposition the navigation bar's origin to (0.0, 0.0) in ViewWillAppear.
self.navigationController.navigationBar.frame = CGRectMake(0.0, 0.0, self.navigationController.navigationBar.frame.size.width, self.navigationController.navigationBar.frame.size.height);
Since you're adding advancedVC as a subview of self.view, it is being added inside the frame of self.view which I'm guessing is already compensating for the status bar.
You can probably easily fix this by adding this line:
nav.view.frame = self.view.frame;
Just above this line:
self.view = nav.view;
-
Other Thoughts
I'm not privy to your entire setup, but self.view may not be needed at all. Simply make your advancedVC instance the rootViewController of the UIWindow instance contained in your App Delegate.
The problem was resolved by fixing the way the navigation controller was inserted. Instead of inserting it into a view that had been put onto the tabbar controller, the navigaiton controller should have been put directly onto the navigation controller.
advancedSearchFormVC = [[AdvancedSearchFormVC alloc] initWithNibName:#"AdvancedSearchForm" bundle:nil];
UINavigationController *searchNavController = [[UINavigationController alloc] initWithRootViewController:advancedSearchFormVC];
This is just one controller that is on the tabbar controller, replacing the advancedSearchFormVC at the same time. Then this nav controller was added to the array of controllers that got put onto the tabbar controller.
Sorry for any trouble, but this was one of those problems I can look directly at and not see it. I should have seen this earlier, because I had another nav controller already on the tabbar controller, and it was set up the same way.
Thanks for your assistance.
The problem is that UINavigationController.view should be added to the top view.
Just find the top one and it will be working great.

Resources