UINavigationBar with UISegmentedControl partially covers childViews

心已入冬 提交于 2020-01-21 05:55:06

问题


I have read many other threads on this and the Apple docs, but haven't found a solution yet for my particular problem.

My app uses a UITabBarController as the rootViewController, and in one of the tabs I have a UISegmentedControl in the navigationBar to switch between three child UITableViewControllers.

(In the real app two of the childVCs are a custom UIViewController, I'm just using three UITableViewControllers for the sample app).

The segmentedControl setup and the switching all works fine. The thing that goes wrong is that only the first UITableViewController is shown correctly. For the second and third one, part of the first cell is hidden under the navigationBar. When I click through all three, the first one is still ok.

I have made a little sample app to show what's going on, using very bright colors for demonstration purposes: https://www.dropbox.com/s/7pfutvn5jba6rva/SegmentedControlVC.zip?dl=0

Here is also some code (I'm not using storyboards):

// AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    FirstViewController *fvc = [[FirstViewController alloc] init];
    UINavigationController *firstNavigationController = [[UINavigationController alloc] initWithRootViewController: fvc];

    SecondViewController *svc = [[SecondViewController alloc] init];
    UINavigationController *secondNavigationController = [[UINavigationController alloc] initWithRootViewController: svc];

    // Initialize tab bar controller, add tabs controllers
    UITabBarController *tabBarController = [[UITabBarController alloc] init];
    tabBarController.viewControllers = @[firstNavigationController, secondNavigationController];

    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.rootViewController = tabBarController;
    [self.window makeKeyAndVisible];

    return YES;
}


// FirstViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    self.title = @"One";
    self.view.backgroundColor = [UIColor orangeColor];

    UITableViewController *vc1 = [[UITableViewController alloc] init];
    UITableViewController *vc2 = [[UITableViewController alloc] init];
    UITableViewController *vc3 = [[UITableViewController alloc] init];

    vc1.view.backgroundColor = [UIColor redColor];
    vc2.view.backgroundColor = [UIColor blueColor];
    vc3.view.backgroundColor = [UIColor greenColor];

    self.viewControllers = @[vc1, vc2, vc3];
    self.segmentTitles = @[@"Red", @"Blue", @"Green"];

    self.segmentedControl = [[UISegmentedControl alloc] initWithItems: self.segmentTitles];
    [self.segmentedControl addTarget: self
                              action: @selector(segmentClicked:)
                    forControlEvents: UIControlEventValueChanged];

    self.navigationItem.titleView = self.segmentedControl;

    self.segmentedControl.selectedSegmentIndex = 0;

 // set the first child vc:  
    UIViewController *vc = self.viewControllers[0];

    [self addChildViewController: vc];
    vc.view.frame = self.view.bounds;
    [self.view addSubview: vc.view];
    self.currentVC = vc;
}

- (void)segmentClicked:(id)sender
{
    if (sender == self.segmentedControl)
    {
        NSUInteger index = self.segmentedControl.selectedSegmentIndex;
        [self loadViewController: self.viewControllers[index]];
    }
}

- (void)loadViewController:(UIViewController *)vc
{
    [self addChildViewController: vc];

    [self transitionFromViewController: self.currentVC
                      toViewController: vc
                              duration: 1.0
                               options: UIViewAnimationOptionTransitionFlipFromBottom
                            animations: ^{
                                [self.currentVC.view removeFromSuperview];
                                vc.view.frame = self.view.bounds;
                                [self.view addSubview: vc.view];
                            } completion: ^(BOOL finished) {
                                [vc didMoveToParentViewController: self];
                                [self.currentVC removeFromParentViewController];
                                self.currentVC = vc;
                            }
     ];
}

So obviously my question is, why does this happen, and what can I do to fix it?

Edit: adding screenshots.

EDIT: Based on the answer below I changed the code in the animation block to:

[self.currentVC.view removeFromSuperview];

if ([vc.view isKindOfClass: [UIScrollView class]])
{
    UIEdgeInsets edgeInsets = UIEdgeInsetsMake(self.topLayoutGuide.length, 0, self.bottomLayoutGuide.length, 0);
    [UIView performWithoutAnimation: ^{
      vc.view.frame = self.view.bounds;
       ((UIScrollView *)vc.view).contentInset = edgeInsets;
         ((UIScrollView *)vc.view).scrollIndicatorInsets = edgeInsets;
     }];
  }
   else
   {
       vc.view.frame = self.view.bounds;
   }

   [self.view addSubview: vc.view];

Now it works. I'm going to try this with a custom UIViewController as well.


回答1:


The issue is that you do not set the correct content inset to each table view. The system attempts to do it for you, but I guess your setup is too complex for it, and it only does it for the first tableview that is loaded in viewDidLoad. In your loadViewController: method, when replacing the currently displayed view, make sure to set both the contentInset and scrollIndicatorInsets to the values of the previous view. I think the system will manage to set the correct insets later, in case you rotate to landscape. Try it. If it doesn't, you will need to do it on your own in viewDidLayoutSubviews.



来源:https://stackoverflow.com/questions/31761396/uinavigationbar-with-uisegmentedcontrol-partially-covers-childviews

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!