I have a TabBarController, one of the tabs of which contains a sub view which is a navigationController. I am then loading into the navigation controller a view which inherits form UITableViewController.
My problem is thta for some reason the table view starts behing the navigation controller, not the top of the screen but about half way down the navigation bar, hence the top of the first cell in the table view is cut off.
Can anyone suggest how to move the UITableViewController down?
Fix it programmatically:
- (void)viewDidLoad {
UIEdgeInsets inset = UIEdgeInsetsMake(20, 0, 0, 0);
self.tableView.contentInset = inset;
}
This "tucked in behind the Navigation bar" issue is due to iOS 7 using fullscreen layout automatically. See the iOS 7 Transition Guide.
It's a bit devious since it displays as in iOS 6 in the Simulator (layout-wise; ie. not tucked in behind).
Is your navigation bar translucent? Mine was, and setting it to non-translucent fixes it on Iphone iOS 6, iPhone iOS 7, and Simulator 7.0 building with XCode 5. (In my case I set it to translucent for visual appearance.)
You can set the frame of the UITableView to an explicit X,Y position by setting the frame property on the view. Or you can change the same property using interface builder depending on whether you've added the tableview via IB or in code.
eg.
myTable.frame = CGRectMake(0.0, myTable.frame.origin.y + NAV_BAR_HEIGHT, myTable.frame.size.width, myTable.frame.size.height);
This will position the table myTable (which is a pointer to the UITableView) below the navigation bar, you may also need to adjust the height of the table accordingly. The height of the nav bar which I am indicating with a constant is 44.0.
I typically do this type of view adjustment if it has been necessary in the viewWillAppear of the view controller responsible. It's not common that you'll need to make this type of adjustment so it may be something you can fix by changing the way your views are being setup.
Without more details of how your view is setup it's hard to be more specific.
Related
I have 'about' controller using Navigation Bar below status bar. For some reason I have to set the background color of View to be the same color of Navigation bar, otherwise, the background of status bar will be white. This trick works fine on other device, but not on iPhoneX's landscape view. As you see below:
If I set the background of View to be white, there will be other issues:
1) The status bar is white.
2) Navigation bar is not extended on landscape view
Looks like this is an issue that I have Navigation Bar inside View as the storyboard structure shown below:
But I cannot seem to be able to move Navigation Bar to the same level as View. Any idea?
Your UINavigationBar is most likely pinned to the safeAreas of the view. There are several things to consider here:
Current setup
Currently, your view is pinned to the safe area insets of its superview. On iPhone X, that is:
UIEdgeInsets(top: 44, left: 0, bottom: 34, right: 0) in Portrait
UIEdgeInsets(top: 0, left: 44, bottom: 21, right: 44) in Landscape
So this is exactly where your view ends up:
The values in safeAreaInsets.bottom don't matter here, because the navigationBar will most likely not expand that far to the bottom of its superview.
Pinning to superview
Ok, now let's pin the view to the edges of its superview instead of to the safe area inset:
(Do that for all 3 edges, adjusting the constant to 0 if necessary)
This is what we end up with:
Looking good for landscape but what's up with portrait? Notice how the bar button sits inside the status bar.
Well, the layout system is doing exactly what you're telling it to do (if that were true all the time, coding for iOS would be a breeze :D). It pins the view to the very top of its superview, ignoring any layoutMargin or safeAreaInsets. For UINavigationBar however, this is not what we want. We want the content of the bar to start at any safeAreaInset.top, so that it does not interfere with the status bar, for example.
Solution
The solution is to revert the top constraint back to 'relative to safeArea'. The content of the navigationBar now looks ok. In order to expand the background of the navigationBar upwards, you set the navigationBars delegate (UINavigationBarDelegate) and provide the following implementation:
func position(for bar: UIBarPositioning) -> UIBarPosition {
return .topAttached
}
By returning .topAttached, you tell the navigationBar to expand its background (blur view) upwards beneath the status bar.
Result:
Note that in general, it would be better to use UINavigationController if possible. This whole layout dance is done for you, plus adding a plain UINavigationBar to a view won't work well with large titles. They need a navigationController providing the collapse and expand logic.
Addendum
A few additional notes on this topic:
We do not need to consider left and right safe areas here. UINavigationBar respects these and insets its content accordingly. It does not do so for vertical insets, that's why we have to do the dance described above.
If you look closely, even the layout in the very last picture is not quite right. The large title is too close to the left edge. To work around this, you would have to tick Preserve Superview Margins for the navigation bar in the storyboard. Again, all these things are handled by the system for you if you simply use UINavigationController in the first place.
You can use two views one for status bar and another for navigation bar and apply constraint as shown and your issue will be fixed.
isTranslucent is set by default to true. Setting it to false will extend the navigation bar below the status bar.
navigationBar.isTranslucent = false
A summary and a little explanation for beginners for CodingMeSwiftly's answer:
In your ViewController class in viewDidLoad method or similar you must assign a delegate (or do it in storyboard):
navigationBar.delegate = self //where navigationBar is an IBOutlet
Make extension for your ViewController class:
extension ViewController: UINavigationBarDelegate {
func position(for bar: UIBarPositioning) -> UIBarPosition {
return .topAttached
}
}
Check that on the storyboard the Navigation Bar top constrain is Safe Area.Top
It works for me.
Looks like standalone Navigation Bar just does not work for this case. After change it to Navigation Item fixed the issue. To make it to be Navigation Item, I choose the existing controller (the one with Navigation Bar) and embed it into Navigation Controller via "Editor -> Embed".
So our app is built using XIB interfaces, not story boards. We have XIBs for iPhone and iPad.
Since the iOS7.1 update the, iPhone xibs are now bigger in interface builder and far too tall when deployed on a device.
The height is all wrong, the XIB is far too tall now. For example, backgrounds appear to go way outside the View when set to fill. When deployed on the phone everything is shifted down about the height of the top nav bar.
If I add/remove Top/Bottom Bars for the View in Interface Builder things shift around but not in a way that makes sense. My app has a nav bar, if I tell the interface builder it has a nav bar then the height of the xib grows a further 80 or so pixels. If I tell the interface builder it has no nav bar, everything shifts up properly but the height of the View is still so tall that backgrounds and stuff near the bottom go off screen.
So for the very vague issue but we are pulling hair over this.
UPDATE
- It seems Opaque Navigation Bar fixes half the problem. We had every interface set with a Translucent Nav Bar. Those do not appear to take up space in IOS7.1 but they did in IOS7.0.
The problem now is still height. It still seems internally the height is broken or starts from a new origin.
In view did load, on a view with a opaque nav bar, on iPod Touch:
self.view.frame.origin.y is showing 0
self.view.frame.size.height is showing 256
Nav bar origin.y = 20
Nav bar size.height = 32
This totals 308, missing 12 pixels.
Create auto layout constraints in IB or programmatically that align the top of the main view in each XIB file to the "top layout guide" and bottom of the views to the "bottom layout guide." This solved a very similar problem when moving from iOS 6 to iOS 7 in several of my apps.
In a UINavigationController I have a UITableView. I use a settings-button to allow users changing some table settings.
When the settings-button is tapped I push a new view onto the navigation stack.
This new view has the following view structure
-> UIView1 411 x 320 px (backgroundColor supposed to be transparent) !!!!
-->> UIView2 270 x 300 px (backgroundColor grey)
--->>> Screen elements
My problem is that I want UIView1 to be transparent so that the information behind is still visible. All my attempts, such as
setting the bg color to transparent
changing the alpha value
removing the Opaque indicator
have failed so far.
Any clues? most appreciated!
UINavigationController is not designed to allow "buried" view controllers to still be showing under the current visible view controller. (The iOS framework can actually unload the views of view controllers on the nav stack that aren't the current top item!)
So if you try to do it, it just won't work, or you'll have problems. (Same goes for modal view controllers on the iPhone -- even if you make the background transparent, the view you're pushing on top of will disappear.)
If you really want the old UI to still be visible underneath, consider presenting your new entire UI as a UIView placed over the current view (i.e. do [existingView addSubview:myNewView]).
I'm having an issue with UITableViewController's tableView changing its frame position when presented from a UITabBarController, within a UINavigationController. The frame is fine when displayed from a regular tab. However, if I move and show the UITableViewController from the 'More' Section, the tableview moves down the same height as the navigation bar (which I don't want it to). When I tested the runtime frame coordinates between proper and nonproper positions, it shows as the same (0.0, 0.0, 320.0, 411.0).
This issue only happens AFTER I've shown the tableView in one Nav Controller and then it's moved and shown in another, like the 'More' VC to the tab, or tab to the 'More' VC
What's going on here and how can I fix this?
The last image is how it looks like when the app launch, as it should be, with he table view right below the nav bar. In the first two however, you can see that the tableview has been moved down.
Thanks in advance!
I was able to solve the issue. It turns out that when you move a UITableView controller within a UINavigationController to the moreNavigationController, 44 pixels are added to the 'top' variables of contentInset and scrollIndicatorInsets. I'm not sure why this is happening or why those 44 pixels aren't being removed when the tableView leaves the 'moreNavigationController', but here's the answer. I'm calling these two lines from within viewWillAppear.
self.tableView.contentInset = UIEdgeInsetsMake(44.0, 0.0, 0.0, 0.0);
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(44.0, 0.0, 0.0, 0.0);
The UITableViewController has this behaviour that it always try to best fit the screen size. UITableViewController is perfect for fullscreen tableview but otherwize I recommend not using the UITableViewController but instead implement a tableViewControler yourself by implementing both the datasource and delegate. Some did set resizeSubViews to NO and solve their problem but I really advice recreate the controller yourself which is not that much work.
Reset autosizing property of table view nib file.
You can find it inside :
Tool>Attribute Inspector
First take a UITableView in the view using XIB. Then add navigation bar and resize the tableview. You will get what do you actually want.
If you still find any problem then please let me know.
If you can display your code, or take a screenshot of your setup, it would be a lot easier. From my experience, creating UITableViewController instances and hooking them up in Interface Builder will expand to fill the screen.
How are you connecting it to the "More" tab? If it's in two tabs, and you're doing ANYTHING dynamic, check your UITableViewController class viewDidLoad method. You shouldn't have to add / delete / re-add the table unless they're separate instances.
Some places to check:
NSLog your tableHeaderView height and position
NSLog your tableFooterView height and position
Create a backgroundView and assign it to the tableView's backgroundView property to see what it's true dimensions are and where it's being displayed
Check where the UITableViewController's view starting position is.
Wish I could help more. Would like to see your setup / code.
Is it possible to resize the UITableView on the RootController of a nav based app? When RootViewController.xib is opened in IB, there isn't a view. Just the UITableView. Clicking the inspector and then the little yellow ruler, frame height is grayed out. I'm adding a toolbar programmatically to the RootViewController:
[toolbar setFrame:rectArea];
That works fine but the bottom cell in the tableview is partially hidden because the tableview doesn't know about the toolbar.
The easiest way, is to adjust the contentInset (which is inherited from UIScrollView). Resizing by setting the frame can cause crazy drawing bugs in cells.
For example, if you are trying to resize a tableview for the keyboard, do something like this:
tableView.contentInset = UIEdgeInsetsMake(0.0, 0.0, 216.0, 0.0);
tableView.scrollIndicatorInsets = tableView.contentInset;
Hope that helps someone. This way worked best for me.
Yes, but you need to have a ViewController (not a UITableViewController) as the root controller for the nav, and wrap the actual UITableView in the UIViewControllers view.
You can still have the UIViewController conform to the UITableViewDelgate and Datasource protocols, and use all the same methods you have now in your UITableViewController.
P.S. you'll get more responses if you use the plain "iphone" tag.
You could also just set the Content and Scroller inset of the tableview
I encountered a similar issue when attempting to display the detail controller by itself, see: http://vimeo.com/13054813
The issue is that the SplitView controller applies its own transform to the sub-controllers, taking them out of the orientation detection loop, which blows goats and seems incredibly 'hackish' for built-in classes. (The video illustrates what happens when you make the detail view the root view, then add it back to the split view and make the split view root while in landscape; you get double rotation of the detail view.)
Unfortunately I've again run into these transformation issues while attempting to resize a SplitViewController's detail sub-view in response to the keyboard appearing/disappearing. In portrait, all works fine, in landscape it's fscked.
Yes, adjust the contentInset and scrollIndicatorInsets are the convenient way to resize the UITableView.
As the answer of Sam Soffes posted, I succeed resize UITableView in UITableViewController for the bottom UIToolbar.