iOS add a custom view to UINavigationBar like Viber app - ios

I want to add a subview (a segment control) like Viber app main screen.
I tried setting self.navigationItem.titleView = myCustomView, but it seems to not working
How can I achieve my goal?

If you are adding this code from a UIViewController inside a UINavigationController, this code should work. So You need to check some points:
This view controller is part of the navigation controller?
The navigation bar is part of the navigation controller?
Are you initializing myCustomView correctly? Is it non-nil when you do this?
Is this view controller in the top of the stack? As written in the docs, and you can see that according to what you see from apps in general, this titleView is only used when item is topmost on the stack.
Try to NSLog the following to check some of them:
NSLog(#"self.navigationItem exists? %d", self.navigationItem != nil);
NSLog(#"customView exists? %d", customView != nil);

Related

Add common views once in navigation controller

What I'm trying to achieve is to design my "shared" part of UI in interface builder and use child view controllers to show content to the user. This may sound as trying to reinvent UINavigationController, but it is not. In fact, the whole thing is embedded in one.
It looks like this :
Now, what I'm trying to do is change child view controllers of this BaseViewController and indicate this change in the navigation bar, so that all of its functionality remains.
I tried adding such a method :
+ (UIViewController *)baseViewControllerWithChild:(UIViewController *)child {
BaseViewController *base = [BaseViewController new];
[base addChildViewController:child];
child.view.frame = base.childViewControllerContainer.frame;
[base.view addSubview:child.view];
[child didMoveToParentViewController:base];
return base;
}
and then using it like this :
- (void)didTouch:(UIButton *)sender {
[self.parentViewController.navigationController pushViewController:[BaseViewController baseViewControllerWithChild:[DummyViewController new]] animated:YES];
}
(Note : DummyViewController is exactly that - a dummy vc, made just for testing, it only has background color set in viewDidLoad)
This method is a handler of a button in first child view controller. So far so good. Unfortunately, the result is not as expected - the pushed view controller is black. At firs I thought this was because BaseViewController was designed in storyboard and initially set as rootViewController of navigation controller. Moving it to a xib file and setting from code didn't quite work for me, as you cannot add a Container View in a xib.
To summarise, I would like to have a base design governed by BaseViewController class and content would be added as a childViewController of it. Pushing a new view controller would be a result of an action on these childViewController and should update the navigation stack accordingly.
Also, the whole thing needs to work with iOS 7.
Any help as to how to try to achieve this is greatly appreciated!
The issue was casued by base.childViewControllerContainer being nil - this was caused byt he fact that view property of view controllers is loaded lazily. Adding [base view] before accesing base.childViewControllerContainer solved the issue, though I'm not sure if this is the one, only and best way to do this.

Second pushed View Controller with UISearchController doesn't receive touches in UINavigationBar

I modified AAPLSearchBarEmbeddedInNavigationBarViewController in Apple's UICatalog sample code so that it pushes another instance of AAPLSearchBarEmbeddedInNavigationBarViewController onto the navigation stack when a cell is selected. In the second view controller the UISearchBar set as the title view of the UINavigationBar (just like the first one) isn't tappable (unlike the first the one). This seems like a bug. How do I fix it? Here is my modified UICatalog code:
https://github.com/stevemoser/UICatalog
Also I tested with with Xcode 6 and 7. It's broken in both.
The solution is to set the first VC self.definesPresentationContext = NO when navigating away from it and making sure to call self.definesPresentationContext=YES in the view did appear so that the visible VC allows defines the presentation context.
Thanks goes to Rory McKinnel who put me on the right track.

Two UINavigationItems?

Could anyone explain why there are two navigationItems? When I log like below:
NSLog(#"%#", self.navigationItem);
NSLog(#"%#", self.navigationController.navigationItem);
I get two different instances of UINavigationItem:
<UINavigationItem: 0x7f85b06f5a20>
<UINavigationItem: 0x7f85b06ab640>
I have only created a UINavigationController programmatically once.
All UIViewControllers have a property navigationItem. Therefore, because UINavigationController is a subclass of UIViewController, it also has this property.
self.navigationItem will be the one presented when your controller is pushed. The documentation for navigationItem, it's clear about this property
This is a unique instance of UINavigationItem created to represent the view controller when it is pushed onto a navigation controller.
self.navigationController.navigationItem would be the item displayed if Apple allowed UINavigationControllers to be nested. However, since this isn't allowed, it's best to forget about it.
Okay, this question puzzled me for awhile but I think I figured it out. self.navigationItem and self.navigationController.navigationItem are two different objects. Here's why:
In iOS, each UIViewController object has a UINavigationItem. The navigationItem for your current view controller is self.navigationController, and self.navigationController.navigationItem is kind of a spillover object, it's the navigationItem for your parent navigationController.

iOS view doesn't display any of it's subviews when added as a subview of NavigationController's view

I have a NavigationController and I want to make a View that animates itself from the top of the screen and sits above navigationBar. I'm initialising viewcontroller from a xib and it works perfectly when I add it as [self.view addSubview:myView]; , but it sits below navigation bar. When I try to add it as [self.navigationController.view addSubview:myView]; it places it on top of navigationBar as intended but view doesn't display any of it's subviews placed in xib. I can't see why this is happening, have been trying to solve this for hours.
UPDATE
My custom view from a xib is paired with custom ViewController class and I added this code in it :
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(#"!!! %i", [self.view.subviews count]);
}
if I add myView to self.view it prints 1 (there's actually 1 subview), but when I add it as self.navigationController.view -viewDidAppear is not even called. But it does appear on the screen with no subviews. Now I'm even more confused.
I think you need use this:
[self.navigationController.navigationBar addSubview:myView];
Why don't you just remove the navigation controller if you don't need it? Another way is to hide the navigation bar so that view occupies complete space and then show the navigation bar again when needed.
I could help more if you provide some code with the views.
Turns out I'm an idiot. It's a really simple scope problem. I was instantiating a local variable of my VC inside the method, and of course it was released at the end. As soon as I assigned my VC to a global variable all started to work like a charm. Easy as that.

What's the proper way to keep UITabBar in all ViewControllers (Don't want to use UITabBarController)

Just to clarify things, I don't want to use UITabBarController. I need to do some custom changes to the UITabBar that can't be done using UITabBarController. (like making it scroll etc')
This is how I've created my UITabBar
From the Interface Builder I've dragged a UITabBar and located it inside a ViewControllers.
Connected the delegate and outlet.
Added UITabbarItem tags and segue identifier.
and used this code:
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
if (item.tag==0) {
[self performSegueWithIdentifier:#"Favorite" sender:nil];
}
else if (item.tag==1)
{
[self performSegueWithIdentifier:#"Item" sender:nil];
}
}
My problem is that when I push a new ViewController the UITabBar disappears.
My question is, what's the right proper way to keep the UITabBar on the pushed ViewController and other ViewControllers ?
I've tried passing it to the next view controller using PrepareForSegue and it works but when I go back to my previous controller I need to reset the UITabBar frame etc'. I guess I can keep it as a global object inside my Singleton and keep adding it to new ViewControllers but that sounds like an over kill
Is there a better way to do it without using a UITabBarController ?
Even if you don't want to use a tab bar controller, you should still follow the same design pattern. Your ScrollableTabBarController should be a container view controller, and when different tab items are selected, it should add the new item as a child view controller. Read the view controller containment documentation for more details.
At the moment it sounds like you're pushing view controllers on top of your container, which suggests that your storyboard is based on a navigation controller. This is the wrong way to do it.
I'm not sure how straightforward it is to do custom container controllers in the storyboard, (I'd do it in code). You may have to make the connections manually rather than via segues.

Resources