Any way to replace navigation item on UINavigationController without pushing view controller? - ios

I've created a view controller that's within the view controller hierarchy of a UINavigationController. This view controller contains a full-frame container view that displays the view of a child view controller.
I'd ideally like to display the items associated with the child view controller's navigation item (i.s., title and rightBarButtonItems) instead of the navigation item of the view controller that contains the container view.
My initial reaction is simply to set viewController.navigationItem = childViewController.navigationItem but navigationItem is read-only. My second reaction is to set the associated items themselves, e.g.:
viewController.navigationItem.title = childViewController.navigationItem.title;
viewController.navigationItem.rightBarButtonItems = childViewController.navigationItem.rightBarButtonItems;
With swizzling, I'm also able to detect when the child view controller's navigation item's properties are set and update accordingly. However, if the child view controller's navigation item's properties are updated without replacement (e.g., title changes text color, rightBarButtonItem is disabled), these changes are not reflected.
Is there any way of achieving the effect I'm looking for?

Hello sir instead of setting childviewcontroller navigation item you can set parentviewcontroller's navigation item.
I mean to say before loading child view controller you can set parentviewcontroller's navigation bar Item if you know childviewcontroller's navigatio bar item value.
I have one more question if you child view controller is inside container how does it have own navigation bar because it would be scrollable so better to set parent view controller's navigation bar before loading child view controller.

Turns out that my problem was elsewhere and that the approach outlined in my question works as desired. x_x
To make this answer more useful, here are more details of my approach:
I created a category on UINavigationItem and swizzled the methods -[setTitle:] and -[setRightBarButtonItems:] using Mattt Thompson's tutorial (http://nshipster.com/method-swizzling/). The swizzled methods simply post custom NSNotifications UINavigationItemTitleDidChange and UINavigationItemRightBarButtonItemsDidChange respectively.
In -[prepareForSegue:sender:] I extract the destination view controller of my embed segue and store it in a custom property childViewController on my view controller.
In the setter for my view controller's childViewController I add observers to my custom UINavigationItem notifications using the navigation item of my child view controller as the object.
When each of these notifications are received, I update the title and rightBarButtonItems of my view controller's navigation item, respectively.
The "elsewhere" in my own fix was that my child view controller wasn't updating its right bar button items when I thought it was, so it appeared as if the view controller presenting it wasn't obtaining its right bar button items.

Related

parentViewController and presentingViewController both are nil

I have a tabBarController with 5 tabs the third tab is a navigation controller with TableViewController as the root view controller.
When I press on a row on the table view it push a detail view (regular view controller) about the selected row.
The problem is first time parentViewController and presentingViewcontroller properties (in the details page) are set, all other consecutive both properties are set to nil.
EDIT
I created a single tab application with navigation controller same as the one in the picture but I did not disable auto layout in the storyboard, every time parentViewController is set correctly.
I believe this is a bug if you disabled auto layout.
You are neither creating a child view controller, nor presenting a modal.
(Pushing a detail view controller onto a navigation controller's stack is kind of like adding a child, but navigation controllers predate the parent/child view controller mechanism, so they don't use it.)
What you need to check is the navigationController property of your detail view controller. That should be non-nil if it was pushed onto a navigation controller stack.

Segue-ing to Embedded view controller

I have have a view controller that is embedded in a UINavigationController and I want to segue to another view controller that is also embedded in a different UINavigationController. If I try to use a push segue, I get an error saying that I can't push a UINavigationController. However, I don't think using a modal segue is appropriate. How should I go about this?
How should I go about this?
You should use a single navigation controller.
the problem is that I want different bar button items for each view controller and they won't change
Each view controller can set up the bar buttons however it likes. Take a look at UINavigationItem. Each view controller has a navigation item, and the navigation item has various properties such as leftBarButtonItems and rightBarButtonItems that you can use to set the buttons.

What is actually inside navigationController's "view" property?

I was going through Apple's documentation about navigation controller and find this point ambiguous and hard to comprehend.
It was written in this online documentation of navigation controller.
Navigation Controller Views
A navigation controller is a container view controller—that is, it
embeds the content of other view controllers inside of itself. You
access a navigation controller’s view from its view property. This
view incorporates the navigation bar, an optional toolbar, and the
content view corresponding to the topmost view controller. Figure 2
shows how these views are assembled to present the overall navigation
interface. (In this figure, the navigation interface is further
embedded inside a tab bar interface.) Although the content of the
navigation bar and toolbar views changes, the views themselves do not.
The only view that actually changes is the custom content view
provided by the topmost view controller on the navigation stack.
From that, my understanding is that inside this "view" property. There should be at least two subview inside this view.One is the navigationBar the other is the contentView of the current displayed viewController’s view. But while I am debugging only the navigation bar showed with another view called UINavigationTransitionView showed.
My question is, is this normal. Have I done anything wrong?
Second, what is the most common way to access current displayed viewController's view with only the reference to the navigation controller.
Thanks
UINavigationTransitionView controller contains one wrapper view which intern will have the current uiviewcontroller's view.
You can probably find this view as a subview of UINavigationTransitionView. However this is not the "right" way to do this. The proper way is to go through property "topViewController" and then take its view:
self.navigationController.topViewController.view
If there is another view controller or its view that you need, you have access to whole view controller's hierarchy across navigation controller through viewControllers property.
self.navigationController.viewControllers
More here:
https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UINavigationController_Class/index.html

Edit parent view controller's title from child

I have app with UICollectionViews in UIPageViewController based on this tutorial for UIPageViewController, now I've embedded main view controller in navigation controller, and I want to change title of nav bar dynamically when in detail view, but how can I access it?
At first I've tried to embed in navigation controller Page View Controller, but nav bar wasn't displayed.
edit:
I've found out, that I can add navigation item to Time Snap Detail View Controller and set its title here, even though it's not visible in storyboard.
But how can I edit title in navigation bar, when I'm in Page View Controller?(In this case, on stack of the navigation controller is Main View Controller, which has Page View Controller as child view controller).
I tried this, and it's ok:
childVC.parentViewController.navigationItem.title = #"abc";
The parent in view controller is not working anymore. Looks like the only way is to save the parent in this child view controller's method and set it's title:
override func didMove(toParent: UIViewController?)
try this. it's working for me in almost same scenario
self.navigationController.parentViewController.navigationItem.title = #"sdfsdf.";

what UINavigationController do with object which calls pushViewController: function?

Is it removes object from superview or just hides that object?
Check the docs :) Its adding it to the stack, not removing it. popViewControllerAnimated: removes it.
The object in the viewController parameter becomes the top view
controller on the navigation stack. Pushing a view controller results
in the display of the view it manages. How that view is displayed is
determined by the animated parameter. If the animated parameter is
YES, the view is animated into position; otherwise, the view is simply
displayed in place. The view is automatically resized to fit between
the navigation bar and toolbar (if present) before it is displayed.
In addition to displaying the view associated with the new view
controller at the top of the stack, this method also updates the
navigation bar and tool bar accordingly. In iOS 3.0 and later, the
contents of the built-in navigation toolbar are updated to reflect the
toolbar items of the new view controller. For information on how the
navigation bar is updated, see “Updating the Navigation Bar.”
http://developer.apple.com/library/ios/documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html#//apple_ref/occ/instm/UINavigationController/pushViewController:animated:

Resources