Update back button in navigationbar - ios

if i change the title of the parentViewController, how do i update the back button displayed in the upper left corner of the child view. ?
i already know to set self.title when i am actually displaying the parent view, but i would like to know how to refresh the button with the new title displayed in the child view while i am looking at the child view. i have tried
self.parentViewController.title = #"foo"
and
self.parentViewController.navigationItem.title = #"foo"

Try this:
self.parentViewController.navigationItem.backBarButtonItem.title = #"foo";

You need to set the title for the navigationItem that belongs to the 'previous' controller. So in a navigationController that would be the one 'to the left'.
You can set this title first and then push the new view onto the stack.

What I ended up doing was implementing a delegate protocol. my child view tells the parent the new name and the parent sets its title. with self.title = #"foo"

Related

How to set Title Bar for multiple tabed view?

I want to add title named News at the top of this view. I tried self.navigationItem.title = #"News" and self.navigationItem.titleView = #"News" but nothing happened. How can i set it ?
I think You have to try this one. In the viewController ViewDidLoad method.
self.title=#"Home";
You just cant add a title directly at top of the view, either you need to take a uilabel in which you will write your title or you have to embed your each view controller with navigation controller

How to name a back button in UISplitViewController

I have UITableViewController (its name is News) and UIViewController (its name is DetailViewController) and UISplitViewController. I want it to show a back button when I use an iPad in portrait orientation. I made the button but I cannot name it. I wrote following code
detailController.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
detailController.navigationItem.leftItemsSupplementBackButton = true
detailController.navigationItem.leftBarButtonItem?.title = navigationController?.topViewController.title
But it doesn't show the name of the button. I see only the arrow (the arrow works).
I also tried the following in my UITableViewController(News) but it didn't help me
I use two segues for different devices with this code.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
var screen = UIScreen.mainScreen().currentMode?.size.height
if (UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad) || screen >= 2000 && UIDevice.currentDevice().orientation.isLandscape == true && (UIDevice.currentDevice().userInterfaceIdiom == .Phone){
performSegueWithIdentifier("showDetailParse", sender: nil)
self.dismissViewControllerAnimated(true, completion: nil)
} else if (UIDevice.currentDevice().userInterfaceIdiom == .Phone) {
performSegueWithIdentifier("showParse", sender: nil)
}
}
My result on an iPad
My result on an iPhone
Thanks to Paul Hegarty and his invaluable lectures at Stanford University and available on iTunes U... in this case his 2013 lectures under the title "Developing iOS 7 Apps for iPhone and iPad" and specifically "Lecture 11 Table View and the iPad".
If you're using storyboards, then:
Open your main storyboard and select the Navigation Controller that links to the Master View Controller in your Split View Controller group;
Open the Inspector;
Under the heading View Controller, against the property Title, enter the words that you would like to appear alongside the "Back" button chevron.
See screenshot of Master Detail Xcode template set up with a Split View Controller...
If you're instantiating views in code, then:
obtain a reference to the Navigation Controller for the Master View controller;
set the title property of that Navigation Controller with the NSString of words that you would like to appear alongside the "Back" button chevron.
As an aside, I would highly recommend implementation of Auto Layout and Size Classes, that you remove the text for the Back Button property and let size classes determine the appropriate words for your Back Button.
For example, as per the question...
The Solution:
Here is the way to fix the issue with the detail view controller's back button:
For any view controller that gets pushed onto the primary navigation controller's stack, set that view controller's title. (Either in its viewDidLoad: method or in the pushing view controller's prepareForSegue:sender: method.)
Set the primary navigation controller's title in the child view controller's viewDidLoad: method.
For example, in MasterViewController.m:
- (void)viewDidLoad {
[super viewDidLoad];
[self setTitle:#"Foo"];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[self navigationController] setTitle:[self title]];
}
This will keep the detail view controller's back button title in sync with the top primary view controller's title.
What Is Going On:
UINavigationController, its rootViewController, and UINavigationItem each have a title property.
Note that the back button shown for a current view controller is actually the previous view controller's backButtonItem. (See Figure 1-7 Navigation bar structure)
A UINavigationController will automatically inherit the value of the title of its root view controller, but will not automatically inherit the title of any other controller that gets pushed onto its stack. This is why, by default, the back button of the detail view controller will always show the title of the primary navigation controller's root view controller. You might allocate, initialize, and push multiple child view controllers, but only one navigation controller is allocated and initialized for each side of a standard split view controller.
Additionally, a view controller's navigationItem's title property (whose value will appear in the label in the center of the navigation bar) does not inherit its value from the navigation controller, but from the view controller itself. If you set the view controller's title property to "Bar", and the containing navigation controller's title to "Foo", the label displayed in the center of the navigation bar will say "Bar".

UIViewController Title attribute in Storyboard

I am setting the title field of a UIViewController via Interface Builder/Storyboard:
This view controller is nested in a UINavigationController which in turn is nested within a UITabBarController. When I run the app, I my navigation item has no title, neither does the tab bar item.
If I explicitly set the view controller's navigation item's title, and also it's tab bar item's title in interface builder, then it works just fine.
I am wondering:
a)If I am not using Storyboard but just regular xibs, setting the title of a view controller implicitly sets the navigation items' title as well as the tab bar item's title. But it's not the same storyboard. Is this the intended behaviour?
b) What is then the purpose of the view controller's title (in Storyboard)? it seems to have no effect.
Thanks!
You can set the title of the UINavigationBar in Storyboard by double clicking the actual navigationBar and typing in a title right there. This only sets the title for the UINavigationBar.
Setting the title in code offers some different possibilities.
self.title = #"Your title"; will set the title of a navigationBar and also cause the title to cascade down to a UITabBarItem, if present.
self.navigationItem.title = #"Your title"; will only set the title of the navigationBar, assuming a UINavigationController is present, and NOT affect a UITabBarItem.
self.navigationController.title = #"Your title"; will set the title of a UITabBarItem but NOT the UINavigationBar.
Step 1
If you're looking at a Xib in Xcode's Interface Builder, take a look in the "Document Outline" panel (second panel from the left). Expand the view controller you're working with until you find an icon labelled: Navigation Item.
Step 2
If you then highlight the Navigation Item and open up the Utilities panel (the farthest on the right), and click the Attributes Inspector, you'll see where you can set the title of the view controller. This is the way to do it in Interface Builder, rather than doing it through code.
I ran into this issue this morning. Here are the stabs I took and the final workaround.
This correctly logs the child view controller's title as set in the storyboard, but has no effect on what's being presented:
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Title: %#", self.title);
}
This has no effect; the title still doesn't show (probably doing an "if (![_title isEqualToString:title]){}" user the hood:
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = [self.title copy];
}
This causes the title to be set correctly:
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *title = self.title;
self.title = nil;
self.title = title;
}
My guess is that the UINavigationController is pulling the title for the view being presented before it has been loaded from the storyboard, but then doesn't start listening for changes until after the property has been set. I don't use storyboards or nibs very often, however, so it's quite possible there's a magic checkbox for this hidden somewhere that I've missed.
In any case, it looks like you can either do the self.navigationItem.title = self.title dance, or the above, as a workaround and still maintain your titles in IB.
Apples docs for this are kinda clear:
The navigation controller updates the middle of the navigation bar as
follows:
If the new top-level view controller has a custom title view, the navigation bar displays that view in place of the default title view.
To specify a custom title view, set the titleView property of the view
controller’s navigation item.
If no custom title view is set, the navigation bar displays a label containing the view controller’s default title. The string for this
label is usually obtained from the title property of the view
controller itself. If you want to display a different title than the
one associated with the view controller, set the title property of the
view controller’s navigation item instead.
Emphasis mine.
I just ran into the same problem. I don't understand why it's not working... It might be on purpose or just be a bug.
To change the title in interface builder, you can click on the navigation item directly and change the title there:
Everything else on this page failed. For now, this worked, in code, in viewDidLoad:
NSString* text = #"My page title";
UIFont* font = [UIFont systemFontOfSize:20.0];
const CGSize SIZE = [text sizeWithAttributes:#{NSFontAttributeName:font}];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, SIZE.width, SIZE.height)];
label.text = text;
label.textColor = UIColor.blackColor;
self.navigationItem.titleView = label;
If you have UINavigationItem present, then you must use the navigation item title in the storyboard. If you don't have a navigation item for a view controller, then the UINavigationController will use the view controller's title property.
Example :
In your storyboard, if you have a navigation item the navigation controller doesn't need to read the view controller's title. Even if the title field is empty for this navigation item.
Remove the navigation item (if you can, you won't be able to do it for the root view controller but you will for the others) and your title will be correctly loaded
I think it works as designed although we expect another behaviour. If you print the title property in - (void)viewDidLoad it will be the same value that you set in story board so I see no reason of this not working unless Apple's choice.
a) If I am not using Storyboard but just regular xibs, setting the title of a view controller implicitly sets the navigation items' title as well as the tab bar item's title. But it's not the same storyboard. Is this the intended behavior?
I believe this is the intended behavior. I think that the purpose of the title attribute of a view controller is more of a property that can be used at the developer's discretion perhaps for distinguishing between controllers.
Another reason for this change I think is that your navigation item's title may need to be different than the tab bar title, since the tab bar title cannot be nearly as long as the navigation title.
b) What is then the purpose of the view controller's title (in Storyboard)? it seems to have no effect.
I think I mentioned this in my first paragraph. I think that the title attribute of a controller is a property that the developer can use perhaps for distinguishing between controllers.
I tried all of the above methods, even tried manually adding a navigation bar but to no avail.
So this is what worked for me.
Remove any navigation bar item you manually added to the view controller and add this to your viewDidLoad method
self.navigationController.navigationBar.topItem.title = #"My Title";
or
self.navigationController.topViewController.title = #"My Title";
In my case I solve with this:
[self.tabBarController.navigationItem setTitle:#"My Title"];

how do I display different views in a view controller using a tab bar

I have a view controller that has a map view and a second view under the a tab bar. How do I go about updating the second view when I press buttons on the tab bar?
I tried:
LocationNotesViewController lnvc = new LocationNotesViewController();
lnvc.View.Frame = MainPageTabBarView.Frame;
MainPageTabBarView = lnvc.View;
Nothing happens...the view doesn't update.
I want to update the second view with different things when a user clicks on the tabbar...
If you put a UIView underlying whatever data you want displayed in it, you can use the IBAction of the tabBar to programtically cahnge out the contents of the UIView.
Or you could have the IBActions of the tabbar create new UIViews on the fly, containing whatever you want inside.
Code to do this would be like explained here: http://www.programmerscountry.com/creating-uiviewcontrols-programatically/.
Not exactly the same, but you will understand how it works from that answer.
To switch UIViewControllers use this piece of code:
UIViewController *viewController =
[self.storyboard instantiateViewControllerWithIdentifier:#"4"];
[self presentViewController:a animated:YES completion:nil];
I think this is a work around - but I was able to make this happen by doing:
LocationNotesViewController lnvc = new LocationNotesViewController();
lnvc.View.Frame = new RectangleF(MainPageTabBarView.Frame.X, MainPageTabBarView.Frame.Y - MainPageTabBarView.Frame.Y, MainPageTabBarView.Frame.Width, MainPageTabBarView.Frame.Height);
MainPageTabBarView.AddSubview(lnvc.View);

iOS Subviews added programmatically are lost when view is reloaded from the storyboard

I have an app with two view controllers. ViewControllerA is a blank view with a tap gesture assigned which allows the user to tab on the view and create a UITextView at the point of the tap. The user can create as many UITextViews as they wish and they are added then programmatically to the view (ViewControllerA) as sub views.
There is also a button which allows the user to change the text font and styling. This triggers a Segue to the second view controller ViewControllerB which then allows the user to set Font, Text Size, Color etc. Once completed the user clicks the DONE button on ViewControllerB and another Segue switches back to the initial view (ViewControllerA).
This all works fine. Except when the user switches back to the initial view (ViewControllerA) from ViewControllerB the view is reloaded from the storyboard and the sub views I have added programmatically are gone.
In view (ViewControllerA) ViewDidLoad and ViewWillAppear are firing just fine so the problem seems to be the initial view is released when the first Segue fires and then recreated from the storyboard on the transition back but the subviews are of course not included as they are not in the storyboard since I added them programmatically.
Any suggestions for a best practice on how to solve this so that the subviews are recreated also when the main view (ViewControllerA) reloads?
Many thanks for any suggestions!
From the question it sounds like you had a segue to the text styles view, then another segue "back to the original" - it doesn't work like that, segues always make new instances of the destination VC. You should have had a modal segue to the text styles view, then dismissed the modal view controller - this would return to your original instance.
Just for the record, I solved this as follows in case anyone else needs a solution.
I created a subview in ViewControllerA which is the size of the main view excluding the Toolbar. I call this canvasView. Then I add all of my ImageViews and TextViews to this canvas view.
Then in ViewControllerA viewWillDisappear I archive the canvasView and all of its subviews to a file like this.
NSString *archivePath = [NSTemporaryDirectory() stringByAppendingPathComponent:#"Canvas.archive"];
BOOL result = [NSKeyedArchiver archiveRootObject:_canvasView
toFile:archivePath];
if (!result) {
NSLog(#"Archive failed to archivePath %#",archivePath);
}
Then in ViewControllerA viewWillAppear I check if there is an existing archive and if so reload it which loads the sub views in the correct order. Otherwise I create an empty canvasView like this.
// If the collageView already exists then restore it from the achive, otherwise initialize a new one.
NSString *archivePath = [NSTemporaryDirectory() stringByAppendingPathComponent:#"Canvas.archive"];
_canvasView = [NSKeyedUnarchiver unarchiveObjectWithFile:archivePath];
if (_canvasView) {
// Restore existing canvasView
[_backgroundView addSubview:_canvasView];
} else {
// Initialize a new canvasView
_canvasView = [[UIScrollView alloc] initWithFrame:CGRectMake(_backgroundView.frame.origin.x,
_backgroundView.frame.origin.y,
_backgroundView.frame.size.width,
_backgroundView.frame.size.height)];
[_backgroundView addSubview:_canvasView];
}

Resources