Add UINavigationBar programmatically to UITableViewController - ios

I've been trying to add a UINavigationBar programmatically to my UITableViewController view. I know I can simply embed the UITableViewController to add a navigation bar, but I don't want to do that due to the way my app is setup.
I have tried the following:
var navBar: UINavigationBar = UINavigationBar(frame: CGRectMake(0, 0, 320.0, 64.0))
navBar.delegate = self
self.view.addSubview(navBar)
self.view.bringSubviewToFront(navBar)
However, the UINavigationBar just sits on the tableview (covering the first row) and scrolls with it.
The only way I have managed to make it stay (statically) at the top is to add it to self.tableView.backgroundView. Whilst this stays in position as the tableView scrolls, the tableView runs over the top of it, instead of underneath!
Can someone please shed some light on the view hierarchy here and tell me where I should be adding it?

Related

Static/fixed Navigation Bar in iOS

I have a Navigation Controller and a Collection View under it inside my app. And there is a problem: I use large title inside my Navigation bar, so everything inside is not static. When I scroll the collection view cells, the title (I created it manually using UILabel() to move it as I want inside the navigation bar) and buttons move up and the navigation bar takes form of iOS 10 navigation bar, I mean its height. You can see it here:
The normal state of my Navigation Bar with "Prefer large titles" On:
It happens when I scroll my Collection View, everything goes up:
So the question is simple: how to make the force constant height for the navigation bar? I want it to become fixed even while scrolling. Are there any ideas? Is it possible?
And the second question, if the first is impossible: Another solution for my problem is to make the Navigation Bar with "Prefer large titles" Off bigger. I tried this code:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let height: CGFloat = 50 //whatever height you want to add to the existing height
let bounds = self.navigationController!.navigationBar.bounds
self.navigationController?.navigationBar.frame = CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height + height)
}
but it worked only for large titles. So how can I make the navigation bar bigger?
Yes, you can make it fixed. It will not scroll if the very first view in the view hierarchy is not a CollectionView/TableView (ScrollView).
Using Storyboard/Xib:
Consider the following image where a tableView and button are added in scene. Here the navigation bar will collapse on scroll of tableView because tableView is the very first view in viewController's containerView hierarchy attached to the navigation bar.
Now to make the navigation bar fixed, if we just change the order of tableView and button as below, it will disable the collapsing of navigation bar.
To change the order of the view, you have to click, hold and move up/down.
If you have only CollectionView in this scene then you can add a placeholder view at the top and set its height to zero as below,
Programmatically:
If you are setting up view's programmatically then you just need to add a placeholder view at the top or add tableView/collection after adding other views.
e.g,
self.view.addSubview(UIView(frame: .zero))
self.view.addSubview(tableView) // or collectionView

Autolayout with Navigation Bar - Remove Specific Constraint

I'm building an application for iOS, which is using a navigation controller. I want to put a view in the titleView, and have it fill the whole width of the navigation bar.
I'm calling setupNavBar in viewDidLoad of the view controller that is embedded in the navigation controller. Here is how I do:
func setupNavBar() {
let navBar = navigationController?.navigationBar
// navBar!.translatesAutoresizingMaskIntoConstraints = false
// navBar!.frame.size.height = CGFloat(100)
let searchBar = UIView(frame: navBar!.frame)
searchBar.bounds = CGRectMake(0, 0, navBar!.frame.width, navBar!.frame.height)
searchBar.backgroundColor = UIColor.brownColor()
navigationItem.titleView = searchBar
}
But the view (brown - "searchBar"), doesn't cover the full navigation bar:
So I figured out that the problem was related to Autoresizing and Constraints, because if I call navBar!.translatesAutoresizingMaskIntoConstraints = false, I can freely set the sizes of views frame, so there must be some constraints that change the view's bounds. But I would like to keep as much of the autolayout behaviour as possible.
Is there a way to only change the contraints on the titleView?
I'm doing everything programmatically, I don't use the storyboard or xib's!
EDIT:
But it doesn't seem like there is any constraints on either navigationItem or navBar:
for someObject in navigationItem.titleView!.constraints {
print(someObject)
}
It doesn't print any constraints. neither if I use navBar.constraints!
EDIT 2:
I have a screenshot from "View UI Hierarchy" from the debug navigator:
It seems that the view(brown) alligns with the Navigation Bar Back Indicator View, maybe this is a clue to what causes the problem?
How come the view is resized?
Two different suggestions here:
1. You can try the
navigationItem.titleView.sizeToFit()
Otherwise you could set the background colour of the navbar to brown as it appears you wish the brown bar to cover the entire width of the navbar. If you want to add other views on top of that you then can.
You could also try to make an outlet to the title view and add an NSLayoutConstraint using
navigationItem.titleView.addConstraint(NSLayoutConstraint: NSLayoutConstraint)
I am not entirely sure whether that will work, however.

How to properly add a UITableView inside a nav and tab controller?

I have a navigation setup where at the top there is a UITabBarController. I then have a tab, which is instantiated by creating a UIViewController placed into a UINavigationController like so:
UIViewController *testVC = [UIViewController new]; // Has UITableView as subview
UINavigationController *testNavVC = [[UINavigationController alloc] initWithRootViewController:testVC];
[self setViewControllers:#[testNavVC]];
The problem that arrises is with the UITableView inside the testVC UIViewController. The table displays properly at the top and is correctly situated underneath the UINavController's nav bar. When you scroll the table view to the bottom, however, the final rows in the table view will be cut off at the bottom of the screen. I found out that I can set the bottom content inset to 100(value will differ based on row height) to correctly display the content. I don't feel like I should need to do that though, and am looking for a better solution.
How can I properly add a UITableView that is nested in this way?
As a side note this all works correctly when using a UITableViewController rather than a UIViewController with the added UITableView. In my case I am needing to use the latter option.
You can try to adjust UITableView bottom inset without hardcoding, by using bottomLayoutGuide property:
tableView.contentInset = UIEdgeInsetsMake(0.0, 0.0, self.bottomLayoutGuide.length, 0.0);
It indicates lowest vertical extent for content, and can be used from iOS 7.
As an alternative you can create bottom NSLayoutConstraint for UITableView with this value.
All of my code was done programmatically and the problem ended up being that I setup the UITableView with the views frame. I switched it over to use autolayout instead and it worked great!

UISearchBar Overlays UITableView - TableView Can't be moved

I've got a TableView and a Search Bar set up and both work fine so far. The problem is that the UISearchBar overlays the first item of my TableView.
I cannot use XIB or storyboards in this project.
The definition and instantiation of the TableView is in a galaxy in a class (imported by a class I import...) far, far away -- not that easy to access.
I move (instantiate) the SearchBar on the screen with:
self.searchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0, 0, 320, 44)];
[self.view addSubview:self.searchBar];
self.searchBar.delegate = self;
I tried moving it to 0,-44 but then the screen does not stay at the SearchBar, it moves back down.
If I try to move the UITableView with:
self.tableView.frame = CGRectMake(0, 0, 320, 500);
it moves the SearchBar as well.
So let's say if I set the origin of the search bar at 0,0 and the origin of the table view at 0,44 I get a screen with (objects in this order):
Grey Space with the height of a search bar/table view cell
Search bar (still overlaying the first cell of my table view
other cells
How can I solve this problem? I think the easiest way would be to add an empty object to my data array so the search bar overlays nothing of importance, but that would not be the nicest way of solving it.
Could anyone tell me how I can add/insert an object to an array and then copy another array into it, beginning with index 1, so my empty object stays in there?
You can use contentInset property on your tableView. Just set the top inset to height of search bar.
self.tableView.contentInset = UIEdgeInsetsMake(self.searchBar.frame.size.height, 0, 0, 0);
This should solve the issue.

How do I position UITableView programmatically while using iOS7's UINavigationBar?

I have a quite regular UIViewController that is a part of a UINavigationController-hierarchy, which naturally makes the view have a UINavigationBar at the top. As we all know, iOS7's navigation bars are very different from previous versions.
If I drag a UITableView into my view in Storyboard, then the 'frame' for the table view is covering the entire view (I.E [tableView setFrame:self.view.frame];). Even behind the NavigationBar.
This makes so that if I scroll, the content will be faintly visible through the bar.
Contrary to most people, I actually like this.
In my current view controller, I would like to create the UITableView programmatically and place it as a subview here. However, I am unable to achieve the same effect this way.
I have tried
UITableView *table = [[UITableView alloc] initWithFrame:self.view.frame];
[self.view addSubview: table];
This makes the 'top scrolling point' stay behind the navigation bar. Imagine a single cell in a tableView, and it's faintly visible through the top bar. If I scroll down, it pops right up behind it. That's the default 'top position'.
I have also tried
CGRect frame = CGRectMake(0, 'nav.y+nav.height', self...width, self...height-y);
UITableView *table = [[UITableView alloc] initWithFrame:frame];
[self.view addSubview: table];
to simply place the table view in the rect below the UINavigationBar, but then I won't get the scrolling transparency effect behind the bar.
I also tried the first example along with this:
[tableView setContentOffset:CGPointMake(0, 'below navbar')];
which makes it stay exactly where I want it to stay, but as soon as I touch it (scroll and release), it scrolls back up behind the navigation bar, and stays there.
What's the programmatic solution to achieve this effect? Do I have to set the offset every time I scroll too far up, or is there a simpler solution? Along with this iOS7-style, I'd imagine they would add something like [tableView setVisibleFrame:] or something..?
Add the table in storyboard like normal but make sure you have it connected to an outlet (we will call it _tableView for now).
Then in your view controller's -viewDidLoad set the top inset to be the status bar plus the navigation bar:
`self.tableView.contentInset = UIEdgeInsetsMake( (self.navigationController.navigationBar.frame.origin.y + self.navigationController.navigationBar.frame.size.height), 0, 0, 0);'
This will make sure that all of the cells will be visible but will also fill the area behind the navigation bar with white so the bar doesn't end up gray.

Resources