如何在 Swift 中为 UIView 子类编写自定义 init?

问题描述 投票:0回答:6

假设我想要

init
一个带有
UIView
String
Int
子类。

如果我只是子类化

UIView
,我该如何在 Swift 中做到这一点?如果我只是创建一个自定义
init()
函数,但参数是 String 和 Int,它会告诉我“在从初始化器返回之前不会调用 super.init()”。

如果我打电话

super.init()
我被告知必须使用指定的初始化程序。我应该在那里使用什么?框架版?编码器版本?两个都?为什么?

ios swift cocoa-touch uiview instantiation
6个回答
235
投票

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)
    }
}

55
投票

我为指定的和必需的创建一个通用的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
      }

}

33
投票

Swift 5 解决方案

您可以尝试在 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
    }
    
    
}



19
投票

这是我在 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"); }
}

这是一个带有示例的完整项目:


12
投票

这是我如何在 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"); }
}

0
投票

非常简单的答案,2024年

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)
    }
}

公式为

  1. required init
    中,设置你添加的属性,然后调用super

  2. 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)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.