简体   繁体   English

如何在 Swift 中为 UIView 子类编写自定义初始化?

[英]How do I write a custom init for a UIView subclass in Swift?

Say I want to init a UIView subclass with a String and an Int .假设我想用StringInt init一个UIView子类。

How would I do this in Swift if I'm just subclassing UIView ?如果我只是UIView我将如何在 Swift 中做到这一点? If I just make a custom init() function but the parameters are a String and an Int, it tells me that "super.init() isn't called before returning from initializer".如果我只是创建一个自定义的init()函数,但参数是一个 String 和一个 Int,它会告诉我“在从初始化程序返回之前没有调用 super.init()”。

And if I call super.init() I'm told I must use a designated initializer.如果我调用super.init()我被告知我必须使用指定的初始化程序。 What should I be using there?我应该在那里使用什么? The frame version?框架版? The coder version?编码器版本? Both?两个都? Why?为什么?

The init(frame:) version is the default initializer. init(frame:)版本是默认的初始值设定项。 You must call it only after initializing your instance variables.只有在初始化实例变量后才必须调用它。 If this view is being reconstituted from a Nib then your custom initializer will not be called, and instead the init?(coder:) version will be called.如果此视图是从 Nib 重构的,则不会调用您的自定义初始化程序,而是调用init?(coder:)版本。 Since Swift now requires an implementation of the required init?(coder:) , I have updated the example below and changed the let variable declarations to var and optional.由于 Swift 现在需要实现所需的init?(coder:) ,我更新了下面的示例并将let变量声明更改为var和 optional。 In this case, you would initialize them in awakeFromNib() or at some later time.在这种情况下,您将在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)
    }
}

I create a common init for the designated and required.我为指定的和所需的创建了一个通用的 init。 For convenience inits I delegate to init(frame:) with frame of zero.为了方便初始化,我委托给init(frame:)框架为零。

Having zero frame is not a problem because typically the view is inside a ViewController's view;零帧不是问题,因为通常视图在 ViewController 的视图中; your custom view will get a good, safe chance to layout its subviews when its superview calls layoutSubviews() or updateConstraints() .当父视图调用layoutSubviews()updateConstraints()时,您的自定义视图将获得一个很好的、安全的机会来布局其子视图。 These two functions are called by the system recursively throughout the view hierarchy.这两个函数由系统在整个视图层次结构中递归调用。 You can use either updateContstraints() or layoutSubviews() .您可以使用updateContstraints()layoutSubviews() updateContstraints() is called first, then layoutSubviews() .首先调用updateContstraints() ,然后调用layoutSubviews() In updateConstraints() make sure to call super last .updateConstraints()确保调用 super last In layoutSubviews() , call super first .layoutSubviews()首先调用超。

Here's what I do:这是我所做的:

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

}

Here is how I do it on iOS 9 in Swift -这是我在 Swift 中的 iOS 9 上的操作方法 -

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

Here is a full project with example:这是一个带有示例的完整项目:

Here is how I do a Subview on iOS in Swift -这是我如何在 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"); }
}

Swift 5 Solution Swift 5 解决方案

You can try out this implementation for running Swift 5 on XCode 11您可以尝试使用此实现在 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
    }
    
    
}


声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM