提问人:shbedev 提问时间:8/28/2019 更新时间:9/28/2021 访问量:2604
如何仅在首次初始化自定义 UIView 时在 LayoutSubviews 中执行代码
How to execute code in LayoutSubviews only when first initialising a custom UIView
问:
我们有一个自定义 UIView,它在 Interface Builder 中使用约束,并且我们修改了此视图以具有我们需要绘制的自定义形状。
形状大小取决于在 Interface Builder 中应用于此自定义视图的约束,因此为了在自定义 UIView 中以正确的大小获取形状,我们需要在 LayoutSubviews 中调用它。
问题是,当在屏幕方向期间调用 LayoutSubviews 时,会将另一个形状添加到屏幕中,因为它是在自定义 UIView 的设置函数中调用的。
可以通过添加一个布尔值来解决此行为,该布尔值确定这是否是第一次调用 LayoutSubviews,并且仅当它是时,然后将形状层添加到视图中。
我在这里和网络上做了一些研究,找到了一篇关于如何用不同的方法实现所描述的行为的文章。
https://thomasclowes.com/ios-when-to-layout-your-views/
作者提到了一个自定义类 BaseView 和一个可以实现的协议来解决这种行为。
该解决方案编写在“UIView 和 layoutSubviews”下。
我正在努力理解解决方案,并想知道是否有人可以澄清并展示有关如何实现本文中提到的解决方案的代码示例。
提前致谢。
class CustomView: UIView {
private var firstTimeInit = true
override func layoutSubviews() {
super.layoutSubviews()
setup()
}
private func setup() {
// Check if the the method was already executed
if firstTimeInit == false { return }
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 0, height: 21))
label.font = UIFont.systemFont(ofSize: 13, weight: .bold)
label.text = "Daily"
label.textAlignment = .center
label.sizeToFit()
addSubview(label)
label.center.x = bounds.midX
let shapePath = UIBezierPath()
shapePath.move(to: CGPoint(x: 0, y: 0))
shapePath.addLine(to: CGPoint(x: frame.width, y: 0))
let shapeLayer = CAShapeLayer()
shapeLayer.path = shapePath.cgPath
shapeLayer.strokeColor = UIColor(hex: 0xD5E5EF).cgColor
shapeLayer.lineWidth = 3
shapeLayer.lineCap = .round
shapeLayer.position.y = frame.height / 2
shapeLayer.lineDashPattern = [frame.width / 2.5, frame.width / 5, frame.width / 2.5] as [NSNumber]
layer.addSublayer(shapeLayer)
firstTimeInit = false
}
}
答:
你为什么不创建你的 and once,将其添加到构造函数中的子视图,然后只用于重新计算它们的框架或模式?UILabel
CAShapeLayer
layoutSubviews
喜欢这个:
class CustomView: UIView {
private let label = UILabel(frame: CGRect(x: 0, y: 0, width: 0, height: 21))
private let shapeLayer = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
label.font = UIFont.systemFont(ofSize: 13, weight: .bold)
label.text = "Daily"
label.textAlignment = .center
addSubview(label)
shapeLayer.strokeColor = UIColor(hex: 0xD5E5EF).cgColor
shapeLayer.lineWidth = 3
shapeLayer.lineCap = .round
layer.addSublayer(shapeLayer)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
label.sizeToFit()
label.center.x = bounds.midX
let shapePath = UIBezierPath()
shapePath.move(to: CGPoint(x: 0, y: 0))
shapePath.addLine(to: CGPoint(x: frame.width, y: 0))
shapeLayer.path = shapePath.cgPath
shapeLayer.position.y = frame.height / 2
shapeLayer.lineDashPattern = [frame.width / 2.5, frame.width / 5, frame.width / 2.5] as [NSNumber]
}
}
这样,您的自定义形状将适应变化,而不会自我复制。frame
显然,如果你使用它,你可能需要实际实现。required init?(coder aDecoder: NSCoder)
评论
一种方法是在自定义视图中使用 didSet 方法。例如
class CustomView: UIView {
var firstTimeInit : Bool = false {
didSet {
layoutSubviews()
}
}
override func layoutSubviews() {
super.layoutSubviews()
// i am only changing the color to check if the layoutSubview is called.
// i have a viewController in storyboard with a UIView Background Color set to gray.
backgroundColor = UIColor.red
}
}
若要使用,请确保在自定义视图中调用 didSet 方法,可以在要加载自定义视图的视图控制器的 viewdidLoad 函数中使用它。
class ViewController: UIViewController {
let customView = CustomView()
override func viewDidLoad() {
super.viewDidLoad()
customView.viewDidSet = true
}
}
评论