自定义 UIView 上的 IntrinsicContentSize 拉伸内容
IntrinsicContentSize on a custom UIView streches the content
我想创建一个自定义 UIView
,其中 uses/offers 一个 IntrinsicContentSize,因为它的高度取决于它的内容(就像高度取决于文本的标签)。
虽然我找到了很多关于如何使用现有视图提供的 IntrinsicContentSize 的信息,但我只找到了一些关于如何在自定义视图上使用 IntrinsicContentSize 的信息 UIView
:
@IBDesignable class MyIntrinsicView: UIView {
override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
context?.setFillColor(UIColor.gray.cgColor)
context?.fill(CGRect(x: 0, y: 0, width: frame.width, height: 25))
height = 300
invalidateIntrinsicContentSize()
}
@IBInspectable var height: CGFloat = 50
override var intrinsicContentSize: CGSize {
return CGSize(width: super.intrinsicContentSize.width, height: height)
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
invalidateIntrinsicContentSize()
}
}
初始高设置为50
draw
方法绘制了一个大小为 25
的灰色矩形
高度改为300
,invalidateIntrinsicContentSize()
称为
在 InterfaceBuilder 中放置一个 MyView
实例没有任何问题。视图不需要高度限制
然而,在 IB 中使用 50
的初始高度。 为什么? IB绘制了灰色矩形,因此调用了draw
方法。那为什么高度没有改成300呢?
同样奇怪的是:设置背景颜色时也会绘制它,也不会调用 super.draw(...)
。这是故意的吗?
我希望视图的高度为 300
,顶部的灰色矩形高度为 25
。但是,当 运行 模拟器中的项目结果不同:
- 视图的高度 =
300
- OK
- 内容高度(= 灰色矩形)= 150(半视图高度)- 不正常
内容似乎从其原始高度 25
拉伸以保持其与视图的相对高度。这是为什么?
尝试从内部更改视图的高度 draw()
可能是一个非常糟糕的主意。
首先,如您所见,更改固有内容大小不会触发重绘。其次,如果是这样,您的代码将进入无限递归循环。
看看对您的 class 所做的编辑:
@IBDesignable class MyIntrinsicView: UIView {
override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
context?.setFillColor(UIColor.gray.cgColor)
context?.fill(CGRect(x: 0, y: 0, width: frame.width, height: 25))
// probably a really bad idea to do this inside draw()
//height = 300
//invalidateIntrinsicContentSize()
}
@IBInspectable var height: CGFloat = 50 {
didSet {
// call when height var is set
invalidateIntrinsicContentSize()
// we need to trigger draw()
setNeedsDisplay()
}
}
override var intrinsicContentSize: CGSize {
return CGSize(width: super.intrinsicContentSize.width, height: height)
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
// not needed
//invalidateIntrinsicContentSize()
}
}
现在,当您通过 IBDesignable
属性 更改 IB 中的固有高度时,它会在您的 Storyboard 中正确更新。
下面是在 运行 时使用它的快速浏览。每次点击(任何地方)都会将 height
属性 增加 50(直到我们超过 300,届时它将重置为 50),然后使固有内容大小无效并强制调用 draw()
:
class QuickTestVC: UIViewController {
@IBOutlet var testView: MyIntrinsicView!
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
var h: CGFloat = testView.intrinsicContentSize.height
h += 50
if h > 300 {
h = 50
}
testView.height = h
}
}
我想创建一个自定义 UIView
,其中 uses/offers 一个 IntrinsicContentSize,因为它的高度取决于它的内容(就像高度取决于文本的标签)。
虽然我找到了很多关于如何使用现有视图提供的 IntrinsicContentSize 的信息,但我只找到了一些关于如何在自定义视图上使用 IntrinsicContentSize 的信息 UIView
:
@IBDesignable class MyIntrinsicView: UIView {
override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
context?.setFillColor(UIColor.gray.cgColor)
context?.fill(CGRect(x: 0, y: 0, width: frame.width, height: 25))
height = 300
invalidateIntrinsicContentSize()
}
@IBInspectable var height: CGFloat = 50
override var intrinsicContentSize: CGSize {
return CGSize(width: super.intrinsicContentSize.width, height: height)
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
invalidateIntrinsicContentSize()
}
}
初始高设置为
50
的灰色矩形draw
方法绘制了一个大小为25
高度改为
300
,invalidateIntrinsicContentSize()
称为在 InterfaceBuilder 中放置一个
MyView
实例没有任何问题。视图不需要高度限制
然而,在 IB 中使用 50
的初始高度。 为什么? IB绘制了灰色矩形,因此调用了draw
方法。那为什么高度没有改成300呢?
同样奇怪的是:设置背景颜色时也会绘制它,也不会调用 super.draw(...)
。这是故意的吗?
我希望视图的高度为 300
,顶部的灰色矩形高度为 25
。但是,当 运行 模拟器中的项目结果不同:
- 视图的高度 =
300
- OK - 内容高度(= 灰色矩形)= 150(半视图高度)- 不正常
内容似乎从其原始高度 25
拉伸以保持其与视图的相对高度。这是为什么?
尝试从内部更改视图的高度 draw()
可能是一个非常糟糕的主意。
首先,如您所见,更改固有内容大小不会触发重绘。其次,如果是这样,您的代码将进入无限递归循环。
看看对您的 class 所做的编辑:
@IBDesignable class MyIntrinsicView: UIView {
override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
context?.setFillColor(UIColor.gray.cgColor)
context?.fill(CGRect(x: 0, y: 0, width: frame.width, height: 25))
// probably a really bad idea to do this inside draw()
//height = 300
//invalidateIntrinsicContentSize()
}
@IBInspectable var height: CGFloat = 50 {
didSet {
// call when height var is set
invalidateIntrinsicContentSize()
// we need to trigger draw()
setNeedsDisplay()
}
}
override var intrinsicContentSize: CGSize {
return CGSize(width: super.intrinsicContentSize.width, height: height)
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
// not needed
//invalidateIntrinsicContentSize()
}
}
现在,当您通过 IBDesignable
属性 更改 IB 中的固有高度时,它会在您的 Storyboard 中正确更新。
下面是在 运行 时使用它的快速浏览。每次点击(任何地方)都会将 height
属性 增加 50(直到我们超过 300,届时它将重置为 50),然后使固有内容大小无效并强制调用 draw()
:
class QuickTestVC: UIViewController {
@IBOutlet var testView: MyIntrinsicView!
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
var h: CGFloat = testView.intrinsicContentSize.height
h += 50
if h > 300 {
h = 50
}
testView.height = h
}
}