在 UITableViewCell 中的不同大小的 UIView 上放置一个遮罩层
Put a mask layer on a UIView of varying size inside UITableViewCell
我有一个 UITableView
,其单元格包含一个子视图,我需要在其上执行三件事:
- 根据特定于此单元格的对象内的值在 运行 时更改其宽度限制
- 根据相同的值更改其背景颜色
- 围绕视图的左上角和左下角,但保持右侧的角不变(因此
layer.cornerRadius
不是一个选项)
我在我的自定义 UITableViewCell
子类中使用以下代码来仅在视图的一侧实现圆角效果,我从 tableView:cellForRowAt:
:
调用
func roundLeadingEdgesOfBar() {
let roundedLayer = CAShapeLayer()
roundedLayer.bounds = viewInQuestion.frame
roundedLayer.position = viewInQuestion.center
roundedLayer.path = UIBezierPath(roundedRect: viewInQuestion.bounds,
byRoundingCorners: [.topLeft, .bottomLeft],
cornerRadii: CGSize(width: 2, height: 2)).cgPath
viewInQuestion.layer.mask = roundedLayer
print("frame: \(viewInQuestion.frame)")
}
然而,当我 运行 这段代码时,我看到的是这样的效果:
上面代码中的 print
语句产生以下输出,表明 viewInQuestion
每次都有相同的帧,但在屏幕上很明显它没有:
frame: (175.0, 139.5, 200.0, 5.0)
frame: (175.0, 139.5, 200.0, 5.0)
frame: (175.0, 139.5, 200.0, 5.0)
frame: (175.0, 139.5, 200.0, 5.0)
所以我假设在调用此函数时视图的宽度约束尚未呈现。当我滚动整个 table 视图直到所有单元格都在视图之外,然后将它们滚动回视图时,一切看起来都是正确的并且打印的框架都不同,就像我期望的那样:
frame: (136.5, 79.5, 238.5, 5.0)
frame: (169.5, 79.5, 205.5, 5.0)
frame: (226.0, 79.5, 149.0, 5.0)
frame: (247.5, 79.5, 127.5, 5.0)
我已经多次阅读 SO 以执行依赖于从 layoutSubviews
中应用的约束的代码,但这给了我相同的结果。我什至尝试从 tableView:willDisplay:forRowAt:
中调用 roundLeadingEdgesOfBar
,但无济于事。
我还发现建议将遮罩层代码放在drawRect:
中。这实际上为我解决了 99% 的问题(将性能问题放在一边),但是仍然有一些极端情况(没有双关语意)留下了很长时间 table 视图,我仍然看到错误的行为。
我最后的办法是通过 performSelector
以 0.00001 延迟调用我的舍入函数,这在某种意义上是有效的,你会在屏幕上看到错误大约一秒钟然后消失 - 仍然远非理想行为,更不用说我必须为此编写的糟糕代码了。
有什么方法可以使用正确的 运行 时间范围在 UITableViewCell
内的视图上可靠地应用形状图层?
我认为你应该做的是,
- 在
cellForRowAtIndexPath
中设置与当前对象相关的属性,尝试在该特定值的 setter 中设置约束。
- 调用
setNeedsLayout
,这将在以后调用 layoutIfNeeded
-> layoutSubviews
- 在您的
layoutSubviews
中设置圆角。
希望对您有所帮助。
我建议创建一个 UIView
subclass 并让它处理舍入,而不是调用函数 "round the edges,"。
例如:
class BulletBar: UIView {
override func layoutSubviews() {
let roundedLayer = CAShapeLayer()
roundedLayer.frame = bounds
roundedLayer.path = UIBezierPath(roundedRect: bounds,
byRoundingCorners: [.topLeft, .bottomLeft],
cornerRadii: CGSize(width: 2, height: 2)).cgPath
layer.mask = roundedLayer
}
}
现在,将单元格中 "bar" 子视图的 class 设置为 BulletBar。使用约束将其固定在右侧和底部并限制高度和宽度。为宽度约束创建一个 IBOutlet
,然后根据需要设置 barWidthConstraint.constant
。
class 本身会处理圆角。
结果:
我有一个 UITableView
,其单元格包含一个子视图,我需要在其上执行三件事:
- 根据特定于此单元格的对象内的值在 运行 时更改其宽度限制
- 根据相同的值更改其背景颜色
- 围绕视图的左上角和左下角,但保持右侧的角不变(因此
layer.cornerRadius
不是一个选项)
我在我的自定义 UITableViewCell
子类中使用以下代码来仅在视图的一侧实现圆角效果,我从 tableView:cellForRowAt:
:
func roundLeadingEdgesOfBar() {
let roundedLayer = CAShapeLayer()
roundedLayer.bounds = viewInQuestion.frame
roundedLayer.position = viewInQuestion.center
roundedLayer.path = UIBezierPath(roundedRect: viewInQuestion.bounds,
byRoundingCorners: [.topLeft, .bottomLeft],
cornerRadii: CGSize(width: 2, height: 2)).cgPath
viewInQuestion.layer.mask = roundedLayer
print("frame: \(viewInQuestion.frame)")
}
然而,当我 运行 这段代码时,我看到的是这样的效果:
上面代码中的 print
语句产生以下输出,表明 viewInQuestion
每次都有相同的帧,但在屏幕上很明显它没有:
frame: (175.0, 139.5, 200.0, 5.0)
frame: (175.0, 139.5, 200.0, 5.0)
frame: (175.0, 139.5, 200.0, 5.0)
frame: (175.0, 139.5, 200.0, 5.0)
所以我假设在调用此函数时视图的宽度约束尚未呈现。当我滚动整个 table 视图直到所有单元格都在视图之外,然后将它们滚动回视图时,一切看起来都是正确的并且打印的框架都不同,就像我期望的那样:
frame: (136.5, 79.5, 238.5, 5.0)
frame: (169.5, 79.5, 205.5, 5.0)
frame: (226.0, 79.5, 149.0, 5.0)
frame: (247.5, 79.5, 127.5, 5.0)
我已经多次阅读 SO 以执行依赖于从 layoutSubviews
中应用的约束的代码,但这给了我相同的结果。我什至尝试从 tableView:willDisplay:forRowAt:
中调用 roundLeadingEdgesOfBar
,但无济于事。
我还发现drawRect:
中。这实际上为我解决了 99% 的问题(将性能问题放在一边),但是仍然有一些极端情况(没有双关语意)留下了很长时间 table 视图,我仍然看到错误的行为。
我最后的办法是通过 performSelector
以 0.00001 延迟调用我的舍入函数,这在某种意义上是有效的,你会在屏幕上看到错误大约一秒钟然后消失 - 仍然远非理想行为,更不用说我必须为此编写的糟糕代码了。
有什么方法可以使用正确的 运行 时间范围在 UITableViewCell
内的视图上可靠地应用形状图层?
我认为你应该做的是,
- 在
cellForRowAtIndexPath
中设置与当前对象相关的属性,尝试在该特定值的 setter 中设置约束。 - 调用
setNeedsLayout
,这将在以后调用layoutIfNeeded
->layoutSubviews
- 在您的
layoutSubviews
中设置圆角。
希望对您有所帮助。
我建议创建一个 UIView
subclass 并让它处理舍入,而不是调用函数 "round the edges,"。
例如:
class BulletBar: UIView {
override func layoutSubviews() {
let roundedLayer = CAShapeLayer()
roundedLayer.frame = bounds
roundedLayer.path = UIBezierPath(roundedRect: bounds,
byRoundingCorners: [.topLeft, .bottomLeft],
cornerRadii: CGSize(width: 2, height: 2)).cgPath
layer.mask = roundedLayer
}
}
现在,将单元格中 "bar" 子视图的 class 设置为 BulletBar。使用约束将其固定在右侧和底部并限制高度和宽度。为宽度约束创建一个 IBOutlet
,然后根据需要设置 barWidthConstraint.constant
。
class 本身会处理圆角。
结果: