I've made hundreds of table view controllers over the last decade and I don't know why this is happening. The content of my UITableView is stuck under my UINavigationBar (with a background color) in my UINavigationController. I was having this problem in an existing project, but to try to figure out the problem I created a fresh new project with nothing else in it.
I created a project.
Created TestTableViewController class that just adds some example sections/rows.
Removed the initial view controller from the storyboard.
Added a UITableViewController and set its class type to be TestTableViewController.
set UITableView's background color to UIColor.systemGroupedBackgroundColor.
Change the UITableViewCell to be Basic type and set its cell reuse id to be "Cell".
Told the storyboard to embed the TestTableViewController in a UINavigationController.
Set that UINavigationController as the Initial View Controller.
When I start the app, the navigation bar is hidden (I believe due to the scrollEdgeAppearance) and when I start to scroll away from the top edge, the nav bar starts to show up.
But I need a background color on my nav bar, so:
In the storyboard, I changed the UINavigationController's nav bar to have a background color.
Now the UITableView content is stuck under the nav bar.
I tried configuring the appearance of the UINavBar in my app delegate:
// in AppDelegate -didFinishLaunchingWithOptions
if (#available(iOS 15.0, *)) {
UINavigationBarAppearance *appearance = [UINavigationBarAppearance new];
[appearance configureWithOpaqueBackground];
appearance.backgroundColor = [UIColor systemRedColor];
UINavigationBar.appearance.standardAppearance = appearance;
UINavigationBar.appearance.compactAppearance = appearance;
UINavigationBar.appearance.scrollEdgeAppearance = appearance;
UINavigationBar.appearance.compactScrollEdgeAppearance = appearance;
}
But that didn't change anything. Next:
I tried creating a subclass of UINavigationController called TestNavController
Updated the storyboard to set the class on the nav to be TestNavController
Adding code to -awakeFromNib and -viewDidLoad to explicitly set the style on the nav bar:
// TestNavController, -awakeFromNib
if (#available(iOS 15.0, *)) {
UINavigationBarAppearance *appearance = [UINavigationBarAppearance new];
[appearance configureWithOpaqueBackground];
appearance.backgroundColor = [UIColor systemBlueColor];
self.navigationBar.standardAppearance = appearance;
self.navigationBar.compactAppearance = appearance;
self.navigationBar.scrollEdgeAppearance = appearance;
self.navigationBar.compactScrollEdgeAppearance = appearance;
}
The content is still stuck under the nav bar. Next I tried to take the storyboard out of the equation and in SceneDelegate.m in -scene:willConnectToSession:options, I swapped out the storyboard created root view controller with an entirely code-based root view controller:
TestTableViewController *testvc = [[TestTableViewController alloc] initWithStyle:UITableViewStyleGrouped];
testvc.view.backgroundColor = UIColor.systemGroupedBackgroundColor;
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:testvc];
self.window.rootViewController = nav;
and it works exactly as expected! So, why are my storyboard configured viewcontrollers and code-base appearance settings showing the wrong thing, while the code-based viewcontrollers look as expected? I've been using different colors in the various locations so that I can tell which code is the one having the effect. Red is being set in the App Delegate, Blue is being set in the TestTableViewController's awakeFromNib on the navigationItem.
I thought this was a problem with the scrollEdgeAppearance, but I've tried setting it via code and nothing seems to work.
Why is my content stuck under the nav bar when I use the storyboard? What am I missing?
Here is a link to download the project:
https://inadaydevelopment.com/stackoverflow/wtf.zip
It's a little hard to say whether this is a bug in the storyboard or not; it might be, and you should probably wrap this up into a nicer example and send it to Apple with a bug report. You should provide two projects, one that does everything in code and the other that does as much as possible in the storyboard.
One thing I can tell you is that I don't see Apple using the Grouped style of table with a section zero header. (Settings app is good place to look.) If you suppress your section zero header by setting the title to nil, things look fine because there is no title text getting stuck under the navigation bar.
If you're going to give the zero section a title when using a grouped style, you're probably going to want to compensate by giving the table section header some padding. That will keep it out from underneath the navigation bar. However, I ended up with zero padding after making some other changes.
Another issue I noticed is that it seems to matter what the footer height is. I got a much better look from your storyboard-based project by deliberately setting the footer height to 1 (it wouldn't let me set it to zero). In the end I wound up setting it to 10.
Plus I think you should set the header and footer estimated heights to 0 rather than leaving them at Automatic.
By playing around with all those parameters in my own project, I was able to get this, which looks to me a lot like your code-based example (except that I made the cells yellow so as to see clearly where they are):
Here are the size settings I ended up with (but you should tweak them more until you're happy):
And that's with
self.tableView.sectionHeaderTopPadding = 0;
This may help...
I took a look at your project and made one change.
Your table view in Storyboard has these settings:
and when I run the app I get this:
Changing only the Sections Header Height and Footer Heights to Automatic:
and I get this:
I created two projects from scratch - one loading the controllers from a Storyboard and one loading via code only - and wrapped everything up into a GitHub repo here: https://github.com/DonMag/wtfTable
Running either wtfSB or wtfNoSB gives me almost identical results (except for the default table background color and slight difference in section header heights):
Related
I have a fundamental question: I have a UINavigationController set as the secondary view of a UISplitViewController and I set its prefersLargeTitle property to true:
self.navigationBar.prefersLargeTitles = true
As the rootViewController of that UINavigationController I have some arbitrary UIViewController containing a UICollectionView or something (just some scrolling content).
The problem now is that the large title is not being display right away. You have to scroll up to reveal it first.
Here's an example of the behavior:
https://imgur.com/a/G4ABHjd
I feel like there's a simple property I'm missing here. Any ideas?
The demonstration video is from an example project for the XCoordinator framework that I happened to have open. I've recreated this behavior in a new project as well, so it shouldn't matter.
Thanks!
Large navigations bars were displayed by default but it suddenly changed to smaller title, probably in a recent update. I'm experience this issue with UICollectionViewController even though to confirm, I add the following code to the viewDidLoad method.
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationItem.largeTitleDisplayMode = .always;
Any leads appreciated! :)
I referred to iOS 11 large-title navigation bar not collapsing and although Apple has resolved the OPs issue, they introduced a new bug wherein if you set prefersLargeTitle and c via code, it results in large titles being displayed only when you manually scroll up.
Fix:
- Check largeTitleDisplayMode via storyboard
- Set largeTitleDisplayMode as "Automatic" via storyboard
- Remove any similar code from your View Controllers
The Apple guy in the What's new in Cocoa Touch WWDC video said that the new large-title navigation bar will magically hook into the top-level scroll view of the underlying view controller and collapse/expand itself automatically while scrolling up and down. (And by "magically", he probably meant that they failed to monkey patch this functionality into the already embarassing UINavigationController-UINavigationBar-UINavigationitem APIs in a usable way, so they had to resort to hooking into some heuristically chosen scroll view behind the scenes)
Even though I was prepared that this "automatic" collapse/expand wouldn't work if I deviate the slightest from the basic UINavigationController + UITableView/UICollectionView setup, it seems that even in this simplest case it doesn't work as expected.
Here's what I have:
A UITabBarController which contains a UINavigationController, which contains a UIViewController, which has a UITableView as its view. Tapping the first cell in the table will push a second view controller on the navigation stack:
No code, just the storyboard.
I've checked "Prefers large titles" for the navigation bar to activate large titles. Now, if I run the app and scroll up/down on the table view, the navigation bar stays the same - large - size; it doesn't collapse:
However, I've found that if I set the second view controller's navigation item to use the small navigation bar (by setting "Large Title" to the value "Never"), then if I open that page and navigate back, the interactive collapse magically starts working on the first page:
Am I missing something here, or is this feature not working properly? Here's the sample project I'm using: https://github.com/tzahola/iOS-11-Large-Title-Navigation-Bar
And by the way, I'm using the officially released iOS 11, not the betas.
2017-09-23 Update: I've sent a bug report to Apple, and opened a ticket on openradar.me: http://www.openradar.me/radar?id=5017601935671296
If there is any other view in addition to tableView, also make sure tableView is on the top of that view(s), right under the Safe Area:
Good news! I've just figured out that if I set "Large Titles" to "Never" on the storyboard, and then set it via code, then it works:
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.largeTitleDisplayMode = UINavigationItemLargeTitleDisplayModeAutomatic;
}
Seems like Apple forgot to handle the case when the navigation item has its largeTitleDisplayMode set via the Interface Builder.
So until they fix this issue, leave "Large Titles" as "Never" on storyboards, and set them via code in viewDidLoad.
You just need to do that to the first view controller. Subsequent view controllers honor the value in storyboard.
Or instead of changing anything in storyboard, do this:
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 11.0, *) {
self.navigationItem.largeTitleDisplayMode = .never
self.navigationItem.largeTitleDisplayMode = .always
}
}
No matter which language!
This is because large titles on navigation item decides whether or not to collapse on the basis of large title behaviour on previous screen navigation item title.
Make sure that addSubview(tableView) placed before others addSuview(someview)
Year 2020, iOS 13.0, this WAS NEVER mentioned here. I literally spent an hour or two for this.
Issue: Large title won't collapse when doing layout programmatically using Snapkit (an autolayout framework)
Solution: SETUP YOUR VIEWS (including navigationController stuff and tableView) inside loadView() NOT in viewDidLoad().
#TamasZahola #mohamede1945
Guys I had the same problem. I was able to resolve this issue by adding following snippet on my first View Controller of Navigation Controller
navigationController?.navigationBar.prefersLargeTitles = true
It's an odd bug. The fix is to toggle OFF prefersLargeTitles in the storyboard and to set this in viewDidLoad of your nav controller's root vc:
navigationController?.navigationBar.prefersLargeTitles = true
TableView of its container should be at the top of ViewController's view hierarchy (RootView on screenshot). Otherwise it won't work.
After upgrading my project to iOS7
when I do a BACK Button and the UINavigationController goes back to the previous page, an ImageView on the top of the screen shifts down.
I use IB to do my layouts. These are my Simulated Metrics:
I have AutoLayout off. Any ideas on what the issue might be? I wasnt sure if anyone wants to see specific code and I didnt want to clutter up the question with too much code.
Updates: Based on the comment questions, I wanted to make these updates:
In no place in the application .h or .m file do I make any changes to the imageview's sizes or location.
In both the viewDidLoad and viewDidAppear I call a user-defined method called recalculateAll but their is no reference at all to any imageview sizes. Just for trying it out I commented out the entire section and ran the code and it still jumps down.
In my init I do programatically set some imageviews (you see the #132 in what appears to be a bubble) using their x and y's.
Here is a typical navigation I use for moving from the view controller to the tableviewcontroller:
GetTimeOffByType *showTimeOffReport = [[GetTimeOffByType alloc] initWithNibName:#"GetTimeOffByType" bundle:nil];
showTimeOffReport.timeOffType = #"Vacation";
[self.navigationController pushViewController:showTimeOffReport animated:YES];
These are all .xib files, no storyboarding at all. Its basically a view controller which has an embedded UINavigationController with 6 buttons. Each time a button is pressed it pushes a UITableViewController passing different parameters and showing different data. The transition I am using to get back to the original UIViewController is simply the iOS generated BACK button (so no code to show for that)
Update#2 Hopefully this will help someone solve this wierd behavior. So if I were to click on the table view cell on showTimeOffReport to get the cell detail and then using BACK navigate all the way back it doesnt jump down.
Update#3 Ok this is something I just discovered : The issue of jumping down or not is related to the translucency of the UINavigationBar. If you have a Translucent = YES it will start from the top of the window. If you have a translucent = NO it will start from the bottom of the UINavigationBar.
You might try setting the new property on UIViewController edgesForExtendedLayout to UIRectEdgeNone.
Here is a good resource that explains more about how view layouts changed in iOS 7.
See Apple Documentation
If you plan to be backwards compatible you will probably need to do some runtime checks and adjust positioning if the device is not running iOS 7.
This might help you..You can try adding UIViewControllerBasedStatusBarAppearance key and set it's value NO in your info.plist
UIViewControllerBasedStatusBarAppearance = NO
I have a TabBarController set as main controller tab, where names were defined using interface builder. Now I would like to change its names programmatically.
How could it be done?
Updated to XCode 8
Since my original answer, a lot has happened: Swift 3, Storyboards, etc. Title is usually the one that all views share, and can be set in the attributes inspector
Also, for more control, you can always drag the UITabBarItem, and UINavigationItem elements from the designer view. You must drag them to the view that's gonna be displayed in the tab bar/navigation controller. Basically they store the info as "I wanna be displayed in tab bar like this".
Hello Scene is getting a TabBarItem added to it, so it can be configured.
These two elements behave exactly as accessing the view controller's .tabBarItem and .navigationItem properties via code. These properties always exist in code if they are child of the corresponding object (nav has navItem, and tab has tabItem), you don't need to add them in storyboard/xib to have them.
This last thing is kinda confusing, since in the storyboard/xib it appears you're adding them to the view controller, but in truth you're just saying "the nib will configure these properties too".
Original Answer
The name that appears on the tab bar comes from the UIViewController's title property,
self.title = #"Name me!";
You can change the title at any point, and it should update the text appearing on the tab bar item. But be wary, do this as soon as possible, ideally, in the init method in use (or initWithNibName:bundle:, or initWithCoder:).
The key here, is that the init methods are called as soon as the tab bar appears on screen, as it initialises all of its view controller. If you were to do it on viewDidLoad, that would only get called if you actually select the tab, then other family of calls, same goes for awakeFromNib, viewWillAppear:, viewDidAppear:, etc.
The idea of having a title on the UIViewController, is to keep things consistent. If you show that viewController on a UINavigationController, the navigation bar on top should use the title property, as it does when using back. The UITabBarController also respects the same title property and changes accordingly.
In terms of reusability, you should be setting the title only from the inside of the UIViewController subclass.
The way of the Nib
Using nibs or storyboards? If you have a UIViewController, you can give it the name straight up in the attributes inspector (or ⌥⌘4)
Unfortunately, if the File Owner is the UIViewController subclass, then you won't be able to access it this way, simply because, XCode registers the File Owner as an "External Object", and doesn't show a configuration panel for it. :(
Multiple titles, same view controller
But sometimes, you just want to have them named differently
// Modify the display title on the tab bar
self.tabBarItem.title = #"World";
// Modify the display title on the navigation bar
self.navigationItem.title = #"Hello World";
Screwing with the neighbours
Each UIViewController should handle his own name, what if you want to force it from the outside (and thus, completely violating the original thing I said about reusability)?
// Rename the other guy's .title property
[[self.tabBarController.viewControllers objectAtIndex:<#Index#>] setTitle:#"Hello World"];
// Or do as before, and rename the other guy's tab bar
[(UITabBarItem*)[self.tabBarController.tabBar.items objectAtIndex:<#index#>] setTitle:#"Hello World"];
You could also probably do it with the navigation item, but that would require more gymnastics than I'm comfortable with.
However it is possible to do it in code, it is better to set this directly in Storyboard. How?
Just tap the appropriate tab bar item inside controller (NOT INSIDE TABBAR CONTROLLER).
Then switch to attribute inspector on the Utilities panel.
Now you are able to change everything:-)
Swift 4+
tabBarController?.tabBar.items![1].title = "xx"
In your viewController.m
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
//Here you are setting title
self.title = NSLocalizedString(#"Title", #"Title");
}
return self;
}
This is how you can change the name and the image of the icon of a tab bar:
self.tabBarItem = [[[UITabBarItem alloc] initWithTitle:#"Main Tab" image:[UIImage imageNamed:#"maintab.png"]] autorelease];
You probably want to do this in UITabBarController::viewDidLoad in which case you need to set the view controller's title because the tab bar items are currently 0 at that point.
So use
[[self.viewControllers objectAtIndex:0] setTitle: #"Buga"];
[[self.viewControllers objectAtIndex:1] setTitle: #"Nuga"];
I'm using Xcode Version 8.2.1 (8C1002) and this works for me: