当我禁用/启用按钮时,视图如何重绘自身?

Posted

技术标签:

【中文标题】当我禁用/启用按钮时,视图如何重绘自身?【英文标题】:How does the view redraw itself when I disable/enable a button? 【发布时间】:2018-04-23 15:25:48 【问题描述】:

如果我启用/禁用按钮……视图会调用什么方法?

我已经在layoutSubviews 上放置了一个断点,但没有看到它到达那里。也不会到达 viewController 的 viewWillLayoutSubviews。所以我只是想知道它是如何工作的以及它触发了什么方法

【问题讨论】:

【参考方案1】:

这是个好问题。我自己对此很好奇,所以我创建了一个简单的UIButton 子类,并在一些被覆盖的方法上设置了断点。以下是我的发现:

    UIButton 子类实例上调用setEnabled:,我在viewDidLoad 中调用MyButton

    这触发了对setNeedsDisplay 方法的调用。它由UIButton 类的setEnabled 方法在内部调用。正如您在此屏幕截图中的堆栈跟踪中看到的那样:

    setNeedsDisplay之后,触发了setNeedsLayout方法。堆栈跟踪与之前的调用类似:

    之后依次调用以下方法:layoutSubviewsdrawLayer:inContext:drawRect:

根据UIView类的Apple's documentation,

当您的视图的实际内容发生变化时,您有责任通知系统您的视图需要重新绘制。为此,您可以调用视图的 setNeedsDisplay() 或 setNeedsDisplay(_:) 方法。这些方法让系统知道它应该在下一个绘图周期更新视图。因为它要等到下一个绘制周期才更新视图,所以可以在多个视图上调用这些方法同时更新它们。

这里是关于UIControlenabled 布尔值的文档:

一个布尔值,指示控件是否启用。 将此属性的值设置为 YES 以启用控件或设置为 NO 以禁用它。启用的控件能够响应用户交互,而禁用的控件会忽略触摸事件并可能以不同的方式绘制自身。将此属性设置为 NO 会将 UIControlStateDisabled 标志添加到控件的状态位掩码;再次启用控件会删除该标志。

他们提到禁用的控件可能会以不同的方式重新绘制自己。他们还提到控件的state 位掩码已更新。所以,我相信,Apple 的内部UIButton 类调用setNeedsDisplay 方法,这反过来又强制重新绘制自己。基于(UIControlState) state 属性,按钮分别绘制自身。您可以在 UIButton 绘图here (look at Table 2 Appearance attributes) 和 UIView 绘图here 上找到更多信息。

但它可能不会在UIViewController 的视图上触发任何事件,该视图将按钮作为子视图。不过,如果您想在视图控制器或按钮的超级视图中监听属性的更改,您可以使用 KVO 并观察 enabled 属性。

【讨论】:

1.所以这一切都发生在UIButton 层?我实际上是在按钮的父视图和视图的父视图上写的。我没有覆盖按钮本身的任何方法。我想这就是全部。 2. 只是为了确定。你是说没有方法冒泡到按钮的超级视图?! 是的,我刚刚注意到您在谈论按钮的超级视图。我相应地更新了我的答案。我不认为按钮的 superview 得到任何事件回调。 只是为了澄清 Pranay:我的层次结构是这样的视图控制器的视图 >> 子视图 >> 按钮(在子视图内)。我正在研究子视图和视图控制器的子视图。您查看了按钮本身。 是的,我查看了按钮本身。我想当您在问题中说“视图会调用什么方法”时,您是在谈论按钮的视图本身。无论如何,在您提到的层次结构中,按钮的超级视图和视图控制器都不会在启用或禁用按钮时获得任何回调。但是如果你想在按钮被启用或禁用时得到通知,你可以使用 KVO。希望我回答了你的问题?

以上是关于当我禁用/启用按钮时,视图如何重绘自身?的主要内容,如果未能解决你的问题,请参考以下文章

如何禁用多个按钮?

如何在按钮单击时在一个视图控制器中正确启用和禁用约束

一次禁用根视图交互并启用子视图交互

在 IBAction 中禁用的 UIButton 重新启用自身

即使 MaterialButton 被禁用,如何让波纹启用?

切换开关 - 当我启用另一个按钮时禁用一个按钮