The UINavigationController built into the container view displays the table view controller with the wrong size

I am trying to find a workaround to this situation:
I have a UITabBarController, one of its segments is connected to the container view controller (BannerViewController), which I use to embed the UINavigationController, the navigation controller clicks the other container view controllers (EventListContainerviewController), each of which contains a table controller. Here is a screen from my story enter image description here
The problem is that the last view of the container is displayed in a smaller frame than their containers. They appear to free up the tab space below. enter image description here
I made all view controllers, a navigation controller, and a tablet controller avoid dropping their edges and adjusting the inserts.

Color means:

Red: Main view BannerContainerViewController 0x7fcc6d38bb00
light green: container view BannerContainerViewController 0x7fcc6d38b860

Blue: main view EventListContainerViewController 0x7fcc6bd7b7c0
Orange: container view EventListContainerViewController 0x7fcc6bd7b690

Something seems to change when the navigation controller adds a blue container, reducing its size by the same amount as a tab (49pt). This can also be seen in the recursive description of the view hierarchy:

<UIWindow: 0x7fcc6bd5af40; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x7fcc6bd4dd80>; layer = <UIWindowLayer: 0x7fcc6bd317c0>> | <UILayoutContainerView: 0x7fcc6bd671c0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7fcc6bd66de0>> | | <UITransitionView: 0x7fcc6bd6a980; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x7fcc6bd6ace0>> | | | <UIViewControllerWrapperView: 0x7fcc6d3a7b20; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7fcc6d3a7db0>> | | | | <UIView: 0x7fcc6d38bb00; frame = (0 0; 320 519); autoresize = W+H; layer = <CALayer: 0x7fcc6d38bbd0>> | | | | | <UIView: 0x7fcc6d38b860; frame = (0 0; 320 519); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7fcc6d38b930>> | | | | | | <UILayoutContainerView: 0x7fcc6d398000; frame = (0 0; 320 519); autoresize = W+H; gestureRecognizers = <NSArray: 0x7fcc6d3a4b50>; layer = <CALayer: 0x7fcc6d387670>> | | | | | | | <UINavigationTransitionView: 0x7fcc6d39cfa0; frame = (0 0; 320 519); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x7fcc6d39cc40>> | | | | | | | | <UIViewControllerWrapperView: 0x7fcc6bf31230; frame = (0 0; 320 519); autoresize = W+H; layer = <CALayer: 0x7fcc6bf31300>> | | | | | | | | | <UIView: 0x7fcc6bd7b7c0; frame = (0 64; 320 406); autoresize = W+H; layer = <CALayer: 0x7fcc6bd7afe0>> | | | | | | | | | | <UIView: 0x7fcc6bd7b690; frame = (0 0; 320 406); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7fcc6bd7aac0>> | | | | | | | | | | | <UITableView: 0x7fcc6f03c400; frame = (0 0; 320 406); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x7fcc6bf34aa0>; layer = <CALayer: 0x7fcc6bf30bc0>; contentOffset: {0, 0}; contentSize: {320, 170}> | | | | | | | | | | | | <UITableViewWrapperView: 0x7fcc6bf35960; frame = (0 0; 320 406); gestureRecognizers = <NSArray: 0x7fcc6bf363e0>; layer = <CALayer: 0x7fcc6bf35ed0>; contentOffset: {0, 0}; contentSize: {320, 406}> | | | | | | | | | | | | | <EventCell: 0x7fcc6bca2950; baseClass = UITableViewCell; frame = (0 85; 320 85); autoresize = W; layer = <CALayer: 0x7fcc6bca2ca0>> 

I am trying to use custom segue instead of presenting a container trying to force a layout, but I think this is a navigation controller error.
Since you can see that the banner does not overlap the view as intended.
enter image description here

Any suggestion?

+6
source share
2 answers

This problem still exists in iOS 10. The UINavigationController, built into the container view, which in turn is contained in the UITabBarController, will display all the views in the navigation stack with additional space for the phantom tab bar at the bottom.

The simplest solution is to subclass UINavigationController and return 'nil' from tabBarController .

 class MyNavigationController: UINavigationController { override var tabBarController: UITabBarController? { return nil } } 

This makes representations in the navigation stack, thinking that they don’t have a tab bar controller, so they won’t leave extra space for it during the layout. I did not notice any negative side effects from this fix, but obviously the views on this navigation controller stack will no longer have access to the tab bar controller. If this is a problem, you can use a more general method to find the tab bar controller (or any "parent" view controller).

For example, if the main view controller for your application is a UITabBarController named "MainViewController", you can extend the UIViewController using a convenient method to find it.

 extension UIViewController { func mainViewController() -> MainViewController? { var vc: UIViewController? = self while !(vc is MainViewController) && vc != nil { vc = vc?.parent ?? vc?.navigationController ?? vc?.presentingViewController } return vc as? MainViewController } } 

This works because the tab bar controller is the parent its direct child view controllers. The above method works through a chain of parent, presentation, and navigation controllers to ultimately reach the child of the tab bar controller, which returns the tab bar controller as the parent.

+6
source

Turns out this is a UIKit error, I filed radar 19996374. Here is the explanation:

When the navigation controller is inside the controller of the tab bar, it is the responsibility to install the content controller (of yours) fully considering the navigation controller. Tab bar controller The dimensions of the navigation controller view correspond to the row of tabs of the border of the controller view. In turn, the accounts of the navigation controller for the height of the tab bar when placing the content controller. Things break when you enter a view controller between the controller tab bar and the navigation controller. The tab bar controller sees that selectedViewController is not a UINavigationController and applies the usual layout rules. But the containing navigation controller sees that its tabBarController property contains a valid UITabBarController and assumes that it is still responsible for handling the height of the tab bar when placing (your) content, view the controller. As a result, the content view controller inserts with the height of the tab bar twice, as you noticed

As a workaround

You can work around this problem by setting the isTranslucent property of the tab bar - YES. Then, in AFBannerViewController, override -edgesForExtendedLayout to return UIRectEdgeAll. AFBannerViewController will now overlap the tab bar (so set the background color for something other than pink), but the navigation controller will apply the correct insertion to the content controller.

+4
source

Source: https://habr.com/ru/post/982741/


All Articles