gpt4 book ai didi

ios - 使用自动版式,当导航栏消失时如何将UILabel保持在同一位置?

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:56:19 26 4
gpt4 key购买 nike

我有一个带有UILabel的视图控制器,当点击一个按钮时它会打印一些单词。轻按按钮后,导航栏将设置为隐藏。

因此,我尝试使用UILabel并在Interface Builder中赋予这些约束:

但是使用这些按钮时,当我按下按钮时,UILabel会跳下,导航栏消失,然后再次返回,进行自我校正,看起来很糟糕。无论导航栏发生什么情况,它都应永久留在原地。

Here's a direct link to a short video showing what happens.

我如何最好地进行设置,以使UILabel保持原位?

项目:http://cl.ly/1T2K0V3w1P21

最佳答案

当您告诉导航控制器隐藏导航栏时,它将其内容视图(即ReadingViewController的视图)调整为全屏,并且内容视图将其子视图布置为新的全屏尺寸。默认情况下,它在任何动画块的之外执行布局,因此新布局立即生效。

要修复它,您需要使视图在动画块内执行布局。幸运的是,SDK包含动画持续时间的常量,该常量隐藏了导航栏,并且动画使用了线性曲线。将hideControls:方法更改为此:

- (void)hideControls:(BOOL)visible {
[UIView animateWithDuration:UINavigationControllerHideShowBarDuration animations:^{
[self.navigationController setNavigationBarHidden:visible animated:YES];
self.backFiftyWordsButton.hidden = visible;
self.forwardFiftyWordsButton.hidden = visible;
self.WPMLabel.hidden = visible;
self.timeRemainingLabel.hidden = visible;
[self.view layoutIfNeeded];
}];
}

这里有两个变化。一种是我使用UINavigationControllerHideShowBarDuration常量将方法主体包装在动画块中,因此动画具有正确的持续时间。另一个变化是我将layoutIfNeeded发送到动画块内的视图,因此视图将动画化为其新的帧。

结果如下:

navigation bar animation

您还可以使用此动画块通过更改其alpha属性而不是hidden属性来淡入和淡出标签。

更新

针对您评论中的问题:

首先,您需要了解运行循环的各个阶段。您的应用始终在其主线程上运行循环。循环非常简化,如下所示:
while (1) {

wait for an event (touch, timer, local or push notification, etc.)

Event phase: dispatch the event as appropriate (this often ends up
calling into your code, for example calling your tap recognizer's action)

Layout phase: send `layoutSubviews` to every view in the on-screen
view hierarchy that has been marked as needing layout

Draw phase: send `drawRect:` to any view that has been marked as needing
display (because it's a new view or it received `setNeedsDisplay` or
it has `UIViewContentModeRedraw`)

}

例如,如果您在hideControls:中放置一个断点,点击屏幕,然后在调试器中查看堆栈跟踪,您将在跟踪中向下看到PurpleEventCallback(在__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__的正上方)。这表明您处于事件处理阶段。 (紫色是App​​le内部iPhone项目的代号。)

如果看到CA::Transaction::observer_callback,则说明您处于布局阶段或绘制阶段。在堆栈的更上方,您将看到CA::Layer::layout_if_neededCA::Layer::display_if_needed,具体取决于您所处的阶段。

这就是运行循环及其阶段。现在,何时将视图标记为需要布局?收到setNeedsLayout时,它被标记为需要布局。例如,如果您更改了视图应显示的内容并且需要相应地移动或调整其大小,则可以发送此消息。但是,在两种情况下,视图会自动发送自己的setNeedsLayout:改变bounds的大小(或改变frame的大小),以及改变subviews数组。

请注意,更改视图的大小或其子视图不会使该视图立即布局其子视图!它只是计划在稍后的运行循环布局阶段对子视图进行布局。

那么...这与你有什么关系?

hideControls:方法中,执行[self.navigationController setNavigationBarHidden:visible animated:YES]。假设visibleNO。以下是导航控制器的响应:
  • 它开始动画块。
  • 它将导航栏的位置设置在屏幕顶部上方。
  • 它将内容视图的高度增加44点(导航栏的高度)。
  • 将内容视图的Y坐标减少44点。
  • 结束动画块。

  • 对内容视图框架的更改导致内容视图发送自身setNeedsLayout

    请注意,对导航栏框架和内容视图框架的更改均采用动画处理。但是内容视图的子视图的框架的尚未更改,但尚未更改。这些更改会在布局阶段稍后发生。

    因此,导航控制器可对顶级内容视图的更改进行动画处理,但不会对内容视图的子视图进行动画处理。您必须强制对这些更改进行动画处理。

    您可以通过以下两个步骤强制使这些更改动起来:
  • 您将创建一个动画块,其参数与导航控制器使用的参数匹配。
  • 在该动画块中,您可以通过将layoutIfNeeded发送到内容视图来强制立即进行布局阶段。

  • layoutIfNeeded documentation说:

    使用此方法可以在绘制之前强制子视图的布局。从接收者开始,只要 super 视图需要布局,此方法就会向上遍历视图层次结构。然后,将整个树布置在该祖先下。

    它通过将layoutSubviews消息从根到叶的顺序发送到树中的视图来布局整个树。如果您不使用自动布局,则在将layoutSubviews发送到视图之前,它还会对每个视图的子视图应用自动调整大小的蒙版。

    因此,通过将layoutIfNeeded发送到内容视图,您将强制自动布局在layoutIfNeeded返回之前立即更新内容视图的子视图的框架。这意味着这些更改发生在动画块内,因此它们的动画(与持续时间和曲线相同)与导航栏和内容视图的更改相同。

    在动画块中布置子视图非常重要,以至于Apple定义了动画选项UIViewAnimationOptionLayoutSubviews。如果指定此选项,则在动画块的末尾,它将自动发送layoutIfNeeded。但是使用该选项需要使用消息的长版本animateWithDuration:delay:options:animations:completion:,因此通常在块末尾自己进行[self.view layoutIfNeeded]会更容易。

    关于ios - 使用自动版式,当导航栏消失时如何将UILabel保持在同一位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17098910/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com