用户点击行时,表视图会在导航栏下面滑动。

4
我有一个包含UITableViewController(TVC0)的UINavigationController(NC)。 当用户点击行时,它会加载UIPageViewController(PVC),该页面在其他UITableViewController(TVC1)之间来回翻页。
TVC0出现在NC里面(这意味着它不会隐藏在顶部的导航栏或底部的选项卡栏后面)。 当它推出PVC时,第一个TVC1出现在导航栏和选项卡栏的边界内。 但是,当我滑动时,内部的TVC1会隐藏在导航栏和选项卡栏后面。 我可以拉出来查看内容,但放开时,它会自动回到栏的后面。
我该如何强制使所有内容都出现在这两个栏之间? 我无法使用Storyboard(因为它是一个旧版应用程序),也没有可用的“嵌入...”选项。
[编辑]
我添加了一些日志记录,并发现我的嵌入式TVC1框架具有绝对起点0,64,但只要我点击,它就会变成0,0。如果我找不到真正的解决方案,我始终可以通过添加64来进行虚假操作,但我更想知道实际上是什么问题。
[/编辑]
[更多编辑]
我正在iOS 6模拟器中测试另一个区域,并发现这种分页在iOS 6中非常完美。因此,我看到的问题是特定于iOS 7的。
[/更多编辑]
以下是我的TVC0的viewDidLoad,PVC的pageViewController:viewControllerBeforeViewController:和一个帮助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];
}

这些视图控制器中,自动布局是开启还是关闭? - foundry
@foundry: 关闭。我尝试了两种方法,但都没有帮助。 - kwiqsilver
2
我曾经遇到过完全相同的问题,花了100多美元的赏金,但最终解决了:http://stackoverflow.com/questions/20258933/ios7-pop-viewcontroller-forces-the-uiimageview-to-drop。基本上Nick Glasso所说的方法是有效的。你在那个屏幕上有一个UINavigationBar吗?如果有,请尝试更改不透明度。如果它不是透明的,似乎也可以解决这个问题。 - logixologist
3个回答

14

我曾经也遇到过类似的痛苦学习经历 :(

将以下代码放入您的视图控制器的初始化函数中:

self.automaticallyAdjustsScrollViewInsets = NO;

在iOS 7中,这是一个新的UIViewController属性,默认值为YES

UIViewController文档


这只是将顶部表视图项隐藏在导航栏后面。 - kwiqsilver
对我来说可以,谢谢。在iOS9和iOS10中与UIPageViewController和NavigationBar一起使用仍然必要:第一张图片垂直错位,触摸它后它会滑动到正确位置。在视图被触摸之前,_UIQueueingScrollView的contentOffset是不正确的。 - ghr

2
你的代码似乎有些混乱。你说这是你的Page View Controller的viewDidLoad,但它创建了一个新的PVC并将其作为子视图控制器添加到其父视图控制器中。如果你真的这样做了,那么你正在在另一个PVC内创建一个PVC。我怀疑这不是你想要的。
这段代码真正属于TVC0,当用户点击一行时调用PVC。这个调用不应该放在viewDidLoad中,但可能很适合放在didSelectRowAtIndexPath方法中。我们可以简单地将其推入我们的navigationController的堆栈中,而不是将其作为子控制器引入。(我预计你在最外层的PVC中已经这样做了)。
但以防万一,我会删除这三行:
    [self addChildViewController: self.pageController];
    [self.view addSubview: self.pageController.view];
    [self.pageController didMoveToParentViewController:self];

将其替换为
    [self.navigationController pushViewController:self.pageController 
                                         animated:YES];

这个函数是从你的TVC0中调用的 - 你展示的所有代码都可以存在于TVC0中。

为了防止你描述的行为,当你创建UINavigationController时,只需将它的navigationBartranslucent属性设置为NO即可。

更新

我已经详细地研究了这个问题,发现在某些情况下确实会出现你所描述的一些错误行为,但很难复制。

“向上跳”的原因很明显。如果你有一个半透明的navBar,并且它的automaticallyAdjustsScrollViewInsets设置为YES,在某些情况下,这可能会导致页面视图控制器的一个私有子视图(_UIQueuingScrollView)在第一次加载页面视图控制器时将其contentOffset.y设置为-64。然而,一旦页面视图控制器有机会更新自己(例如通过滑动或其他触摸手势),它就会重置内部子视图的状态,失去那个流氓的contentOffset。所以当你触摸第一页时,它会向上跳。然后就停在那里了。这可能被认为是一个bug,尽管它可能是错误使用页面视图控制器的结果。

仅将automaticallyAdjustsScrollViewInsets设置为NO并不能解决你的问题,因为这样你的页面都会被定位在navBar的后面。你需要调整页面视图控制器本身的框架。

我可以提供更多详细信息,但此时很难将答案应用到你的特定情况中,因为你的应用程序设计看起来有点奇怪,这可能是问题的原因之一。

  • 如果你可以将导航控制器的导航栏的translucent属性设置为NO,问题应该就会消失了。

  • 正如我之前提到的,我无法完全按照你描述的方式复制你的问题,所以我认为你没有给出一个完整和清晰的应用程序设计图景。

  • 将一个pageViewController作为tableViewController的子视图,并使它的视图成为tableView的子视图,是一种非常奇怪的方法,肯定会导致你的问题。

  • viewControllerBeforeViewController中,pageViewController子视图似乎弹出了它的父视图控制器(即tableViewController) - 所以你永远不会看到它的表内容?也许还有更多相关的应用程序细节,或者你没有准确地描述它。

我建议你首先处理这些问题。你的问题很可能会消失。


@kwiqsilver - 如果这段代码已经在TVCO的viewDidLoad中,我不太明白TVCO如何‘pushes PVC’,因为你在viewDidLoad中将其添加为子视图。至于你的问题,无论哪种方式都应该可以解决——关键是要在navigationController的navBar上将'translucent'设置为NO。但如果我使用'pushViewController'而不是parent/child,则只有在完全按照您描述的方式进行时才能_复现_该问题。 - foundry
1
我尝试了这个,但它只是使我的页面视图控制器的内容变空白了。 - kwiqsilver
@kwiqsilver,你尝试过仅将导航栏的“translucent”属性更改为NO吗?(不更改其他任何内容) - foundry

2
因为您正在一个小于屏幕全尺寸的容器中呈现视图控制器,所以您需要设置:
self.pageViewController.definesPresentationContext = YES; 

 viewControllerWhichIsApageInPageController.modalPresentationStyle = UIModalPresentationCurrentContext

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接