【问题标题】:iOS7 Custom ViewController transition and Top Layout GuideiOS7 自定义 ViewController 过渡和顶部布局指南
【发布时间】:2013-11-16 08:09:13
【问题描述】:

我在我的应用程序中实现了一个自定义 UIViewController 转换,它取代了推送动画中内置的导航控制器。

到目前为止一切正常,除了新推送的视图控制器中的 toplayoutguide 为 0,尽管新视图控制器继承了旧视图控制器的导航栏。 它应该是 64.0(状态栏高度 + 导航栏高度),现在是 0.0。 因此,连接到情节提要顶部布局指南的所有对象现在显得过高 64 点(低于半透明条)。

当我禁用自定义视图转换时,顶部布局指南将具有预期值。 我试图“到处”调用 layoutSubviews 和 updateConstraints。在视图控制器以及导航控制器中。

据我了解,navigationcontroller (parentviewcontroller) 应该更新新视图控制器的 toplayoutguide,但显然我在自定义转换代码中遗漏了一些内容,这会触发 toplayoutguide 更新为正确值。

这是我的自定义转换代码,它是一个设置为导航控制器委托的对象:

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
    return 0.7;
}

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    UIView *animationContainerView = [transitionContext containerView];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView *toView = [toVC view];
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIView *fromView = [fromVC view];

    CGRect endFrame = [transitionContext finalFrameForViewController:toVC];
    CGRect startFrame;

    startFrame = CGRectOffset(endFrame, 0, endFrame.size.height);

    if (self.operation == UINavigationControllerOperationPop) {
        [animationContainerView insertSubview:toView belowSubview:fromView];
        [toView setFrame:endFrame];
    }
    else{
        [toView setFrame:startFrame];
        [animationContainerView insertSubview:toView aboveSubview:fromView];
    }

    [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 usingSpringWithDamping:0.7 initialSpringVelocity:0.8 options:UIViewAnimationOptionBeginFromCurrentState animations:^{

        if (self.operation == UINavigationControllerOperationPop) {
            [fromView setFrame:startFrame];
            [fromView layoutIfNeeded];
        }
        else{
            [toView setFrame:endFrame];
            [toView layoutIfNeeded];
        }

    } completion:^(BOOL finished) {
        [transitionContext completeTransition:YES];
    }];
}

那里没有什么特别的事情发生。只是视图从底部向上滑动并带有一些内置动态。

问题是,附加到顶部布局指南的对象现在位于导航栏下方,因为顶部布局指南长度 == 0。

我不知道我需要做什么,因此将视图控制器的 toplayoutguide 设置为正确的值。

推送导航是通过推送故事板segue“普通”执行的。在调用 performSegueWithIdentifier 之前,我所做的只是设置 navigationcontrollers 委托。

代码如下:

    self.navigationController.delegate = [[My_CustomNavigationTransitionDelegate alloc] init];
    [self performSegueWithIdentifier:@"infosSegue" sender:nil];

我错过了什么?

【问题讨论】:

  • 我遇到了同样的问题。令人抓狂的是,转换完成后,旋转设备会将 topLayoutGuide 更新为正确的值。我还没有弄清楚要调用什么来强制 topLayoutGuide 作为此过渡的一部分进行更新。
  • 对我来说它看起来像一个错误。我已经在苹果开发者论坛上发布了同样的问题,但没有收到任何答案。现在我求助于没有透明的导航栏,而不是丑陋的解决方法。幸运的是,客户仍然没有看到和理解半透明导航栏的优势,因为他们仍然习惯于以前的样子。但这很快就会改变。我希望在那之前 Apple 的某个好心人会告诉我们如何强制更新布局指南...
  • 我遇到了同样的问题,最终实现了我自己的 topLayout 指南视图并对它进行了约束,而不是对 topLayoutGuide。不理想。仅在有人被卡住并寻找快速破解解决方案时才将其发布在这里github.com/stringcode86/SCTopLayoutGuide
  • 我也确实有自己的顶部和底部布局约束。目前看来,如果您使用故事板,它似乎是唯一的解决方案。

标签: ios iphone objective-c ios7


【解决方案1】:

我能够通过以下视图层次结构解决此问题:

UIView
 UIScrollView
  <content, constrained to UIScrollView>

约束 UIScrollView 以匹配 UIView's 顶部、前导、后沿和底部边缘。 Interface Builder 可能希望您对UIScrollView 使用topLayoutGuide 和bottomLayoutGuide,或者它可能不会。也许这取决于 Xcode 的版本,但是我们的一些 View Controller 使用了 superview,其他使用了布局指南。

对于 Interface Builder 不想相对于其父视图约束滚动视图的视图,我在文本编辑器中打开故事板并手动调整滚动视图上的约束。

最后,在 View Controller 上,确保 top bar 下的 extend edges 为 YES,Adjust Scroll View Insets 也是如此。

基本上,我避免使用 topLayoutGuide,而是依赖滚动视图插图,这确实有效。

我在层次结构中没有 UIScrollView,就像你一样,不扩展顶部栏下的边缘对我有用。

【讨论】:

  • Ui,这对我来说太过分了,为了避免遇到问题而将所有内容都塞入滚动视图。是的,我现在正在做的不是在导航栏下方延伸,而是牺牲了透明导航栏,否则我希望它是透明的。
  • (...ups, hit return by wrong) 我的问题是,当使用自定义视图控制器转换而不是使用标准时,navigationcontroller 不执行顶部布局指南更新,构建-in,视图控制器推送转换。
  • 至于在文本编辑器中打开情节提要:您不需要这样做。只需删除附加到“错误”布局指南的约束,然后使用 IB 右下角的“pin”菜单创建一个新约束。在那个“pin”菜单中,您有一个下拉菜单,以便选择要附加约束的其他项目。在那里选择您的超级视图而不是“顶部布局指南”。
【解决方案2】:

我遇到了一个问题,bottomLayoutGuide 属性会将自身设置为零长度,然后会导致标签栏上方的按钮下降到带有自动布局的标签栏下方。

你有没有想过这样做

[self.navigationController.view setNeedsLayout]

我将它放入我的 viewwillappear 中,并且我不再在 bottomLayoutGuide 属性上获得零长度。也许这对您的topLayoutGuide 属性也有帮助。

【讨论】:

  • 不,我的情况不是这样。您是否使用自定义过渡控制器?我到处尝试了 setNeedsLayout,但它并没有解决问题。
  • 我有更好的解决方案!我遇到了同样的问题,经过一秒钟的探索,我在属性检查器中找到了相关视图控制器上的“扩展边缘”复选框部分。我取消选中“Under Bottom Bars”和朋友,等等!布局现在再次自动工作。
  • 这实际上是正确的答案,除了您必须确保视图实际显示。您必须使用 viewDidAppear: 方法而不是 viewWillAppear:。这是因为 UINavigationBar 将在调用此方法时完全设置(并且您的转换此时只会调用完成处理程序)。
  • 我把这段代码放在 didAppear 中,但它适用于幻灯片动画,不会立即更新 ui .. 有什么解决方案吗?谢谢
【解决方案3】:

我遇到了完全相同的问题。我的自定义导航控制器的 容器视图 没有约束。在我将容器视图的垂直间距约束添加到其父视图的布局指南(尽管两者的大小相同)并在 容器视图 上设置顶部/底部/状态栏外观的那一刻,一切都很好并且推送控制器的布局指南处于正确位置。希望对您有所帮助。

更新:来自official documentation on topLayoutGuide

容器视图控制器中的视图控制器不设置此属性的值。相反,容器视图控制器将值限制为指示: 导航栏的底部,如果导航栏可见 状态栏的底部,如果只有一个状态栏可见 视图控制器视图的顶部边缘,如果状态栏和导航栏都不可见

因此,容器视图需要实现正确的约束和隐藏/显示条等,以使效果起作用。 AFAIK 在自定义容器视图控制器中没有 API 可以做到这一点。

【讨论】:

  • 是否有任何示例代码显示了您添加新约束的方式和位置?我想知道您是在视图层次结构的初始设置期间还是在自定义 VC 转换过程中这样做的。
  • 我正在使用故事板——我的设置有一个初始视图控制器,它由我的自定义导航控制器的视图通过嵌入 segue 填充。这是我在 Interface Builder 中完成的,所以在我的视图层次结构的初始设置期间,它们是在任何转换发生之前设置的。我认为您不需要在过渡期间添加约束,因为屏幕尺寸在运行您的应用程序的过程中不会改变(除了重新定向)。希望这会有所帮助。
【解决方案4】:

我找到了办法。首先取消选中控制器的 "Extend Edges" 属性,之后导航栏将变为深色。将视图添加到控制器并设置顶部和底部 LayoutConstraint -100。然后将视图的 clipsubview 属性设为 no(用于 navigaionbar 半透明效果)。我的英语不好对不起。 :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-23
    • 2014-11-15
    • 2014-03-12
    • 2015-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-27
    相关资源
    最近更新 更多