如何强制视图呈现自己?

Posted

技术标签:

【中文标题】如何强制视图呈现自己?【英文标题】:How to force a view to render itself? 【发布时间】:2011-03-23 16:09:06 【问题描述】:

在我的应用程序中,我有许多小的子视图。当用户点击一个子视图时,我将一个单独的视图放在点击的子视图的顶部(相同大小),然后将这个单独的视图动画化为全屏大小。

放大视图是自定义绘制的,这给这种方法带来了很大的问题。如果我在主视图的 viewDidLoad 方法中创建放大视图并将其框架设置为全屏大小,则立即调用视图的 drawRect 方法,并且视图正确呈现全尺寸。如果我在动画中使用这个视图,一切都会按预期进行。

但是,我需要这个放大视图根据被点击的子视图而有所不同,所以我每次都需要重新创建/重新绘制它。问题是,当我为响应触摸事件执行此操作时,视图的 drawRect 方法在动画开始之前不会被调用,此时视图的框架很小而不是全屏,因此一切都是画错了。

在我的触摸事件代码中,我明确地将视图的框架设置为全屏并在开始动画之前调用setNeedsDisplay,但这没有任何效果 - 只是在动画开始之前不会调用drawRect

有没有办法强制重绘,以便在视图的框架是我想要的大小时绘制视图?

【问题讨论】:

我相信乔在他的问题Is there a way to make drawRect work right NOW??! 中提出了类似的问题,Tom's answer 可能会实现您的目标。 @Brad:效果很好,谢谢。如果您将评论作为实际答案,我会选择它。这是有效的代码行:[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate: [NSDate date]]; 很高兴工作。我之所以发表评论,是因为我不太确定我是否理解您的要求,至于何时需要进行重绘。此外,[CATransaction flush] 可以做你想做的事,而不需要你操纵运行循环。但是,您应该在触发动画之前使用它,因为它可能会干扰它们。 @Joe:如果你能在我的 iPhone 问题出现时更加努力地回答它们,我实际上也许可以回到我的音乐软件上。 :) 在 setNeedsDisplay 在类似情况下为我工作后调用 [CATransaction flush]。 【参考方案1】:

正如我在上面评论的那样,Joe 提出了类似的问题(作为一个更普遍的问题)here,Tom Swift provided an answer 操纵了当前的运行循环。

他的建议是在您使用以下代码调用-setNeedsDisplay 后立即强制运行循环进行一次迭代:

[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate: [NSDate date]];

这种方法有一些注意事项,在那里的 cmets 中进行了讨论。

另外,有人指出

[CATransaction flush];

也可以达到强制立即重绘视图的相同效果。

【讨论】:

【参考方案2】:

做到这一点的正确方法是简单地划分你的方法。

只需调用setNeedsDisplay,然后在没有动画的情况下返回。等到正确设置所有内容的drawRect 完成重绘,然后让它排队另一个方法来启动您想要的动画(通过排队操作或通知)。然后开始动画。这一切都可以很快发生(以帧速率),并且不涉及额外的(危险的)递归运行循环调用或CATransaction 调用(这可能会导致额外的 GPU 设置)。

【讨论】:

我认为这行不通。我的问题本质上是我试图将视图从非常小到全屏设置动画,但我需要确保它最初是(通过 drawRect)全尺寸渲染的,以便在全尺寸下看起来最好。我可以让视图呈现全尺寸的唯一方法 - 而不实际在屏幕上显示它,我不想在动画结束之前这样做 - 是使用布拉德答案中的两种方法之一。 【参考方案3】:

在调用setNeedsDisplay 之后,drawRect 可能需要一点时间才能被调用。以短暂(0.1f)的延迟开始您的动画。如果这样更容易,您还可以从 [self performSelector:withObject:afterDelay:] 调用动画方法来添加延迟。

【讨论】:

我实际上尝试过这个,但是由于视图以 0.0 的 alpha 开始动画,所以我在开始动画之前等待多长时间并不重要 - drawRect 在动画之前不会被调用实际开始。操作系统基本上是在说“我不会渲染这个东西,除非我必须这样做”,这是有道理的。【参考方案4】:

一位 Apple 工程师提供了另一种推荐的解决方案。使用 2 个 UIViews,一个小一个大,一个大一个的 alpha 为 0。渲染两者,设置大一个小的框架,并让动画交叉淡入淡出以及从小到大缩放两个尺寸。

【讨论】:

以上是关于如何强制视图呈现自己?的主要内容,如果未能解决你的问题,请参考以下文章

如何关闭自己的视图控制器并在按钮点击中呈现另一个视图控制器?

如何在 iOS 8 中强制视图控制器方向?

如何将关闭按钮从 swiftui 视图的主结构(由 uihostingviewcontroller 呈现)分离到它自己的结构?

iOS 6 中的模态视图控制器强制横向方向

如何在一种情况下推送视图控制器,但在另一种情况下以模态方式呈现它?

如何关闭模态视图控制器,然后立即让呈现视图控制器呈现不同的模态视图控制器?