ios - iOS 12、Xcode 10:UIView setNeedsDisplay(_:) 似乎坏了
问题描述
更新到 Xcode 10 后,我意识到draw(_ rect: CGRect)
我的应用程序中的自定义 UIView(从 UIView 派生的类)的例程调用了错误的rect
. 实际上,它总是以rect
底层 UIView 的全帧调用,而不是rect
由setNeedsDisplay(_ rect: CGRect)
.
这是一个可以作为游乐场运行的代码片段,至少在我的设置中显示了上述在简约设置中描述的错误行为:
import Foundation
import UIKit
import PlaygroundSupport
class CustomView: UIView {
override func draw(_ rect: CGRect) {
print("rect = \(rect)")
}
}
let customView = CustomView(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: 200.0, height: 200.0)))
PlaygroundPage.current.liveView = customView
print("test")
customView.setNeedsDisplay(CGRect(origin: CGPoint.zero, size: CGSize(width: 100.0, height: 100.0)))
我得到的输出是
矩形 = (0.0, 0.0, 200.0, 200.0)
测试
矩形 = (0.0, 0.0, 200.0, 200.0)
rect 的第一个打印输出是视图的标准完整重绘,但打印“test”后的第二个输出会产生问题。由于customView.setNeedsDisplay
之前调用而重绘的输出应该是较小的指定矩形(0.0, 0.0, 100.0, 100.0)
。
所以我明显的问题是:
- 你能重现这种行为吗?
- 我错过了一些明显的东西吗?
- 这是一个错误吗?
解决方案
这实际上是 iOS 12 的新动态后备存储功能有意为之。
什么是后备商店
后备存储用于存储绘制的视图,并且需要为此分配内存。该内存量取决于视图的大小,因为它本质上是颜色和像素之间的映射。
如果您要绘制灰度图像,但内存已分配给广色域,那么这将导致大量空的分配内存(灰度的占用空间低于 RGBA)。为了解决这个问题,动态后备存储功能通过绘制视图的全部内容来工作,然后计算出它需要多少内存,而不是从一开始就假设一切都需要宽色背景。
这样做的连锁反应是您不能重新绘制视图的较小子部分,因为这可能会改变这个商店。
如何绕过它
这是一个很棒的新功能,但如果您确实需要解决它,您可以在您的视图中禁用动态后备存储。这样做的方法是显式设置contentsFormat
views 的属性layer
。
您可以选择与灰度、RGBA 8 位和 RGBA 16 位(宽色)相关的三个选项
所以只需调用:
layer.contentsFormat = .RGBA16Float
你setNeedsDisplay(_ rect: CGRect)
将再次开始按预期工作
您可以在此处阅读该属性:https ://developer.apple.com/documentation/quartzcore/calayer/1792104-contentsformat
还有一个来自 WWDC 18 的精彩演讲,解释了新的动态后备存储并(非常安静地)提到了这种技术
https://developer.apple.com/videos/play/wwdc2018/219/?time=1451
推荐阅读
- angular - FormGroup 不适用于带有 Angular 7 的 Ionic
- angular - 角度 svg 图像预览
- c++ - 如何在 C++ 应用程序中包含外部 PCH 文件?
- excel - 多层枢轴以不同方式处理层(SUM,MAX,SUM)
- sql - Postgresql 在特定时间间隔内创建的记录百分比
- containers - Podman 的权限问题
- docker - Docker compose:将随机容器端口传递给环境变量
- python - Python矩阵给出与最后一条记录相同的结果
- xamarin - xamarin表单列表视图中的粘性标题
- javascript - 反应 onClick 键码未定义?