假设我想要
init
一个带有 UIView
和 String
的 Int
子类。
如果我只是子类化
UIView
,我该如何在 Swift 中做到这一点?如果我只是创建一个自定义 init()
函数,但参数是 String 和 Int,它会告诉我“在从初始化器返回之前不会调用 super.init()”。
如果我打电话
super.init()
我被告知必须使用指定的初始化程序。我应该在那里使用什么?框架版?编码器版本?两个都?为什么?
init(frame:)
版本是默认的初始化程序。您必须仅在初始化实例变量后调用它。如果此视图是从 Nib 重建的,那么您的自定义初始化程序将不会被调用,而是会调用 init?(coder:)
版本。由于 Swift 现在需要实现所需的 init?(coder:)
,我更新了下面的示例,并将 let
变量声明更改为 var
和可选。在这种情况下,您可以在 awakeFromNib()
或稍后的某个时间初始化它们。
class TestView : UIView {
var s: String?
var i: Int?
init(s: String, i: Int) {
self.s = s
self.i = i
super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
我为指定的和必需的创建一个通用的init。为了方便起见,我委托给帧为零的
init(frame:)
。
零帧不是问题,因为视图通常位于 ViewController 的视图内;当您的自定义视图的超级视图调用
layoutSubviews()
或 updateConstraints()
时,您的自定义视图将获得一个良好、安全的机会来布局其子视图。系统在整个视图层次结构中递归地调用这两个函数。您可以使用 updateContstraints()
或 layoutSubviews()
。首先调用 updateContstraints()
,然后调用 layoutSubviews()
。在 updateConstraints()
中,确保调用 super last。在 layoutSubviews()
中,先调用 super 。
这就是我所做的:
@IBDesignable
class MyView: UIView {
convenience init(args: Whatever) {
self.init(frame: CGRect.zero)
//assign custom vars
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
commonInit()
}
private func commonInit() {
//custom initialization
}
override func updateConstraints() {
//set subview constraints here
super.updateConstraints()
}
override func layoutSubviews() {
super.layoutSubviews()
//manually set subview frames here
}
}
您可以尝试在 XCode 11 上运行 Swift 5 的实现
class CustomView: UIView {
var customParam: customType
var container = UIView()
required init(customParamArg: customType) {
self.customParam = customParamArg
super.init(frame: .zero)
// Setting up the view can be done here
setupView()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupView() {
// Can do the setup of the view, including adding subviews
setupConstraints()
}
func setupConstraints() {
// setup custom constraints as you wish
}
}
这是我在 iOS 9 上使用 Swift 进行操作的方法 -
import UIKit
class CustomView : UIView {
init() {
super.init(frame: UIScreen.mainScreen().bounds);
//for debug validation
self.backgroundColor = UIColor.blueColor();
print("My Custom Init");
return;
}
required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented"); }
}
这是一个带有示例的完整项目:
这是我如何在 Swift 中的 iOS 上创建子视图 -
class CustomSubview : UIView {
init() {
super.init(frame: UIScreen.mainScreen().bounds);
let windowHeight : CGFloat = 150;
let windowWidth : CGFloat = 360;
self.backgroundColor = UIColor.whiteColor();
self.frame = CGRectMake(0, 0, windowWidth, windowHeight);
self.center = CGPoint(x: UIScreen.mainScreen().bounds.width/2, y: 375);
//for debug validation
self.backgroundColor = UIColor.grayColor();
print("My Custom Init");
return;
}
required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented"); }
}
class TemperatureGraph: UIView {
var data: [Temperature]
required init(data: [Temperature]) {
self.data = data
super.init(frame: .zero)
}
required init?(coder aDecoder: NSCoder) {
self.data = []
super.init(coder: aDecoder)
}
}
另一个例子
class TemperatureGraph: UIView {
var data: YourDataClass
required init(data: YourDataClass) {
self.data = data
super.init(frame: .zero)
}
required init?(coder aDecoder: NSCoder) {
self.data = YourDataClass()
super.init(coder: aDecoder)
}
}
另一个例子
class TemperatureGraph: UIView {
var height: Int
var color: UIColor
required init(height: Int, color: UIColor) {
self.height = height
self.color = color
super.init(frame: .zero)
}
required init?(coder aDecoder: NSCoder) {
self.height = 180
self.color = .blue
super.init(coder: aDecoder)
}
}
公式为
在
required init
中,设置你添加的属性,然后调用super
在
coder
init 中,将添加的属性设置为您喜欢的默认值,然后调用 super
就是这样。
请注意,您不必必须传入值,只要在调用 super 之前初始化它们(在两次调用中)即可。
例如
class Countdown: UIView {
var seconds: Int
required init() {
self.seconds = 10
super.init(frame: .zero)
}
required init?(coder aDecoder: NSCoder) {
self.seconds = 10
super.init(coder: aDecoder)
}
}