【问题标题】:iOS - How to initialize custom UIView with specific Frame from NIBiOS - 如何使用来自 NIB 的特定 Frame 初始化自定义 UIView
【发布时间】:2018-08-06 04:32:32
【问题描述】:

我想知道用特定框架初始化自定义 UIView 的最简洁方法是什么。

UIView 是根据 XIB 文件设计的。

这是我的实现

class CustomView : UIView {

    @IBOutlet var outletLabel: UILabel!

    public required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupView()
    }

    public override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }

    private func setupView() {

        // Set text for labels
    }
}

这是我想在我的 ViewController 中初始化它的方式:

let screenSize: CGRect = UIScreen.main.bounds
let screenWidth = screenSize.width
let frame = CGRect(x: 0, y: 0, width: screenWidth - 50, height: 70)

let customView = CustomView.init(frame: frame)

但它不起作用,我有一个没有任何插座的白色 UIView。

如果我这样做:

// Extension to UIView to load Nib
let customView : CustomView = UIView.fromNib()

我可以从XIB 文件中看到我的view,它的宽度/高度在Interface Builder 中使用。

我想从XIB 文件中加载view 的具体框架是什么?

我是否遗漏了一些关于初始化的内容?

【问题讨论】:

  • 你需要展示你是如何从 XIB 获得你的视图的。
  • 你不能同时用frame和xib“初始化”,但是你可以从xib加载视图然后改变它的frame。尽管我建议您尽可能保持自动布局并避免显式更改框架。
  • PS:为什么不用 ViewController 初始化视图?
  • @MichaelVorontsov 这个自定义 UIView 是为了当用户在 App 中按下一个按钮时,它会显示一个 Tooltip。我需要根据屏幕大小设置视图宽度。
  • 如果您使用故事板并且工具提示位置已修复,我会建议您创建容器视图控制器,根据需要设置约束并将其隐藏。然后,您可以在需要时显示它。如果您也想在代码中添加所有内容 - 我再次建议您实例化视图,然后设置它的约束。最新的 SDK 使它很容易做到,但您可以使用 SnapKit 使其更加明显,例如 cocoapods.org/pods/SnapKit 我强烈建议使用自动布局,因为 Apple 不赞成使用过去 4 或 5 年的框架。

标签: ios swift uiview xib init


【解决方案1】:

你可以有一个 NibLoading 类,比如:

// NibLoadingView.swift
//source:https://gist.github.com/winkelsdorf/16c481f274134718946328b6e2c9a4d8
import UIKit

// Usage: Subclass your UIView from NibLoadView to automatically load a xib with the same name as your class

@IBDesignable
class NibLoadingView: UIView {

    @IBOutlet weak var view: UIView!

    override init(frame: CGRect) {
        super.init(frame: frame)
        nibSetup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        nibSetup()
    }

    private func nibSetup() {
        backgroundColor = .clear

        view = loadViewFromNib()
        view.frame = bounds
        view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.translatesAutoresizingMaskIntoConstraints = true

        addSubview(view)
    }



    private func loadViewFromNib() -> UIView {
        let bundle = Bundle(for: type(of:self))
        let nib = UINib(nibName: String(describing: type(of:self)), bundle: bundle)
        let nibView = nib.instantiate(withOwner: self, options: nil).first as! UIView
        nibView.anchorAllEdgesToSuperview()
        return nibView
    }

}

extension UIView {
    func anchorAllEdgesToSuperview() {
        self.translatesAutoresizingMaskIntoConstraints = false
        if #available(iOS 9.0, *) {
            addSuperviewConstraint(constraint: topAnchor.constraint(equalTo: (superview?.topAnchor)!))
            addSuperviewConstraint(constraint: leftAnchor.constraint(equalTo: (superview?.leftAnchor)!))
            addSuperviewConstraint(constraint: bottomAnchor.constraint(equalTo: (superview?.bottomAnchor)!))
            addSuperviewConstraint(constraint: rightAnchor.constraint(equalTo: (superview?.rightAnchor)!))
        }
        else {
            for attribute : NSLayoutAttribute in [.left, .top, .right, .bottom] {
                anchorToSuperview(attribute: attribute)
            }
        }
    }

    func anchorToSuperview(attribute: NSLayoutAttribute) {
        addSuperviewConstraint(constraint: NSLayoutConstraint(item: self, attribute: attribute, relatedBy: .equal, toItem: superview, attribute: attribute, multiplier: 1.0, constant: 0.0))
    }

    func addSuperviewConstraint(constraint: NSLayoutConstraint) {
        superview?.addConstraint(constraint)
    }
}

然后您的视图将继承 NibLoadingClass,如:

class YourUIView: NibLoadingView {
    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

在 File's Owner 中设置您的 XIB 类,例如: 在这种情况下,它将是YourUIView

然后实例化它:

let myView = YourUIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width-60, height: 170))

【讨论】:

  • 这抛出了我“必需的'初始化程序'init(coder:)'必须由'NibLoadingView'的子类提供”。
  • 它可以工作,但是对于这个小用例来说有点复杂
  • 同意上一个。评论。将一个视图包裹在另一个视图中只是为了设置它的框架绝对是个坏主意。
  • 始终开放以建议更好的代码。我已经使用了多年,并且在设备兼容性、向后兼容性、新 iOS 版本或任何其他问题上完全没有问题。但同样,每个人都在这里学习,所以任何更好的解决方案都值得赞赏
  • 你是救生员!我花了一周的时间,我所缺少的只是“view.translatesAutoresizingMaskIntoConstraints = true”。非常感谢!
【解决方案2】:

您可以像这样创建自定义类...

import UIKit

class CustomView: UIView {

class func mainView() -> CustomView {
    let nib = UINib(nibName: "nib", bundle: nil)
    let view = nib.instantiate(withOwner: self, options: nil).first as! CustomView
    return view
}

override init(frame: CGRect) {
    super.init(frame: frame)
    let view = CustomView.mainView()
    view.frame = frame
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}


}

在你想要的地方初始化视图...

let view = CustomView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
view.backgroundColor = UIColor.blue
self.view.addSubview(view)

【讨论】:

  • 这不起作用,它显然会给我带来致命错误。但这正是我想要的那种初始化。
猜你喜欢
  • 2017-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多