table view slides up under navigation bar when use

2020-07-18 07:57发布

I have a UINavigationController (NC) containing a UITableViewController (TVC0). When the user taps a row, it loads a UIPageViewController (PVC), which pages back and forth between other UITableViewControllers (TVC1).

TVC0 shows up inside NC (meaning it doesn't hide behind the navigation bar at the top or the tab bar at the bottom). When it pushes PVC, the first TVC1 appears inside the bounds of the nav bar and tab bar. However when I swipe, the TVC1s inside are hidden behind the navigation bar and tab bar. I can pull to reveal the contents, but when I release, it snaps back to behind the bar.

How can I force everything to appear between the two bars? I can't use storyboard (because it's a legacy app) and the embed in... option isn't available.

[Edit]

I added some logging and discovered that my embedded TVC1s frame has an absolute origin of 0, 64, but as soon as I tap, it goes to 0, 0. If I can't figure out a real solution, I can always fake it by adding 64, but I'd much rather figure out what's actually wrong.

[/Edit]

[More Edit]

I was testing another area in the iOS 6 simulator and discovered that this paging works flawlessly in iOS 6. So the issue I'm seeing is iOS 7 specific.

[/More Edit]

Here is my TVC0 viewDidLoad, PVC pageViewController:viewControllerBeforeViewController:, and a helper viewControllerAtIndex::

- (void) viewDidLoad
{
    [super viewDidLoad];
    NSDictionary* options = [NSDictionary dictionaryWithObject:
                             [NSNumber numberWithInteger: UIPageViewControllerSpineLocationMin]
                                                        forKey:
                             UIPageViewControllerOptionSpineLocationKey];
    self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:
                           UIPageViewControllerTransitionStyleScroll
                                                          navigationOrientation:
                           UIPageViewControllerNavigationOrientationHorizontal
                                                                        options: options];

    self.pageController.dataSource = self;
    self.pageController.view.frame = self.view.frame;
    NSArray* viewControllers =
            [NSArray arrayWithObject: [self viewControllerAtIndex: self.initialIndex]];

    [self.pageController setViewControllers: viewControllers
                                  direction: UIPageViewControllerNavigationDirectionForward
                                   animated: NO
                                 completion: nil];

    [self addChildViewController: self.pageController];
    [self.view addSubview: self.pageController.view];
    [self.pageController didMoveToParentViewController: self];

    for (UIGestureRecognizer* recognizer in self.pageController.gestureRecognizers)
    {
        if ([recognizer isKindOfClass: [UITapGestureRecognizer class]])
        {
            recognizer.enabled = NO;
        }
    }
}

// SearchResultsList is TVC1
- (SearchResultsList*) viewControllerAtIndex: (NSUInteger) index
{
    if (index >= self.items.count)
    {
        return nil;
    }

    SearchResultsList* retVal = [[SearchResultsList alloc]
                                    initWithNibName: @"SearchResultsList" bundle: nil];

    MyListItem* myItem = [self.items objectAtIndex: index];
    MyMatchesRequest* matches = [[MyMatchesRequest alloc] initWithItemId: myItem.itemId];
    [matches execute: ^(MySearchResults* results)
     {
         retVal.tableData = [NSMutableArray arrayWithArray: results.items];
         retVal.view.frame = self.view.frame;
         retVal.myItem = myItem;
         retVal.index = index;
         self.title = myItem.displayText;
         [[retVal tableView] reloadData];
     }];

    return retVal;
}

- (UIViewController*) pageViewController: (UIPageViewController*) pageViewController
      viewControllerBeforeViewController: (UIViewController*) viewController
{
    SearchResultsList* vc = (SearchResultsList*)viewController;
    if (vc.index == 0)
    {
        [self.navigationController popViewControllerAnimated: YES];
        return nil;
    }

    return [self viewControllerAtIndex: vc.index - 1];
}

3条回答
兄弟一词,经得起流年.
2楼-- · 2020-07-18 07:59

You code seems a little confused. You say it is your Page View Controller's viewDidLoad, yet it creates a new PVC and adds it as a child view controller to itself as parent. If you are really doing this, you are creating a PVC inside another PVC. I doubt this is what you want.

This code really belongs in TVC0 which invokes the PVC when the user taps a row. This invocation wouldn't be correct in viewDidLoad, but might sit nicely in a didSelectRowAtIndexPath method. Instead of bringing it in as a child controller, we can simply push it onto our navigationController's stack. (I expect you are doing this anyway in your outermost PVC).

But just in case, I would remove these three lines:

    [self addChildViewController: self.pageController];
    [self.view addSubview: self.pageController.view];
    [self.pageController didMoveToParentViewController:self];

and replace them with

    [self.navigationController pushViewController:self.pageController 
                                         animated:YES];

(this is called from your TVC0 - all of the code you have shown can live in TVC0)

Then to prevent the behaviour you describe, when you create your UINavigationController it should suffice to set the translucent property of it's navigationBar to NO.

update

I have looked at this issue in sufficient detail to see some buggy behaviour as you describe occur in some circumstances, but it's fairly hard to replicate.

The cause of the 'jump-up' behaviour is clear. If you have a translucent navBar, and it's automaticallyAdjustsScrollViewInsets is set to YES, in certain situations this can result in a private subview of the pageViewController (_UIQueuingScrollView) setting it's contentOffset.y to -64 when the pageViewController is first loaded. However as soon as the pageVC gets a chance to update itself (for example by a swipe or other touch gesture) it resets it's internal subviews state, losing that rogue contentOffset. So when you touch the first page, it jumps up. Where it then stays. This may be considered a bug, although it may be the result of misusing the pageViewController.

Just setting automaticallyAdjustsScrollViewInsets to NO doesn't cure your ills, as then your pages are all positioned behind the navBar. What you need to do is adjust the frame of the pageViewController itself.

I could go in to more detail, but at that point it gets hard to apply answers to your specific case as your app design looks a little odd, which is probably contributing to the issue.

  • if you can set your navigation controllers' navigation bar's translucent property to NO the problem should go away.

  • as I mentioned earlier, I cannot replicate your issue exactly as you describe, so I think you have not given a full and clear picture of your app design

  • loading a pageViewController as a child of a tableViewController, and making it's view a subview of the tableView, is a very odd way to go, and is doubtless contributing to your problems.

  • In viewControllerBeforeViewController the pageViewController child seems to pop it's parentViewController (the tableViewController) - so you would never see it's table contents? Either there is more relevant detail to the app, or you haven't described it accurately.

I recommend you first deal with these issues. Your problem may well then disappear.

查看更多
做自己的国王
3楼-- · 2020-07-18 08:13

I had a very painful learning experience with similar behavior :(

Put this in your view controller's init:

self.automaticallyAdjustsScrollViewInsets = NO;

This is a new UIViewController property that defaults to YES in iOS 7

UIViewController Docs

查看更多
虎瘦雄心在
4楼-- · 2020-07-18 08:18

Because you're presenting view controllers in a container which is less than the full size of the screen you need to set

self.pageViewController.definesPresentationContext = YES; 

 viewControllerWhichIsApageInPageController.modalPresentationStyle = UIModalPresentationCurrentContext
查看更多
登录 后发表回答