TIMEX TIMEX - 5 months ago 140
Swift Question

Setting edgesForExtendedLayout affects its parent ViewController

In my navigation stack's child, I set

edgesForExtendedLayout = .None

When I click the back button, the UITableView in my parent gets "moved up", as if the navigation bar doesn't exist. (The Navigation Bar covers the table).

Why does the child's edge setting affect its parent? I only want it to affect the current viewController.

In my parent, this is how I created the UITableView:

self.tableView.delegate = self
self.tableView.dataSource = self

self.tableView.frame = CGRectMake(0, 0, screenWidth, CGRectGetMinY(self.tabBarController!.tabBar.frame))
self.tableView.tableFooterView = UIView(frame: CGRectZero)
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 100.0
self.tableView.clipsToBounds = true
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine
self.tableView.separatorColor = UIColor(hex: 0xededed)
self.tableView.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0)
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
self.tableView.layoutMargins = UIEdgeInsetsZero

Could it be that I am setting the tableView's frame incorrectly? I want the table to start below the navigation bar, but end before the tab bar.


It sounds like this might be the correct behavior, but the opposite of what you are expecting.

edgesForExtendedLayout = .None means that the view controller's view will not extend under the top navigation bar or the bottom tab bar. You say that your child view controller is set to edgesForExtendedLayout = .None but not the parent view controller. And that when you go back to the parent view controller, the table view moves under the nav bar. If you did not set the parent view controller in your example to edgesForExtendedLayout = .None, then it will still be using the default of edgesForExtendedLayout = .All. And that will extend the top of the table view under the top and bottom bars.

For the behavior you are looking for, try setting edgesForExtendedLayout = .None on the parent view controller with the table view. So your parent view controller code could look something like this:

self.edgesForExtendedLayout = .None

self.tableView.delegate = self
self.tableView.dataSource = self

self.tableView.frame = CGRectMake(0, 0, screenWidth, screenHeight - self.navigationController!.navigationBar.bounds.height - self.tabBarController!.tabBar.bounds.height)

UPDATE -- To implement the same result using auto layout (preferred over manual frames), first make sure that the table view is already added as a subview of the view controller's main view, then you can simply set up the constraints as follows:

tableView.topAnchor.constraintEqualToAnchor(view.topAnchor).active = true
tableView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor).active = true
tableView.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor).active = true
tableView.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor).active = true

Using these NSLayoutAnchor convenience methods assumes iOS 9 or above. Of course an even easier approach would be to create the view controller in a Storyboard and just ctrl+drag the constraints in place. Either way, whether the constraints force the table view under the nav bar and tab bar or not will still be controlled by the view controller's edgesForExtendedLayout property. In a storyboard, you can control those setting by checking these different boxes in the inspector for the view controller:

storyboard inspector