将UIViewController视图属性设置为不带故事板/笔尖的自定义UIView类 [英] Set UIViewController view property to custom UIView class without storyboard / nib

查看:58
本文介绍了将UIViewController视图属性设置为不带故事板/笔尖的自定义UIView类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个名为LoginViewControllerUIViewController.我想在名为LoginView的自定义UIView类中完全以编程方式构建该LoginViewController的视图,而不是在我的LoginViewController中构建所有元素.这样,我就可以防止Controller类(MVC)中的查看"代码.

I have a UIViewController called LoginViewController. I want to build the view of that LoginViewController fully programmatically in a custom UIView class called LoginView instead of building all the elements within my LoginViewController. This way I'm preventing "View" code in a Controller class (MVC).

在下面的代码中,我将LoginViewController的视图设置为LoginView,为简单起见,其中仅包含2个UILabels

In the code below I'm setting the view of my LoginViewController to my LoginView which for simplicity only contains 2 UILabels

class LoginViewController: UIViewController {

override func loadView() {
    super.loadView()

    self.view = LoginView(frame: CGRect.zero)
}

LoginView类初始化两个标签,并应设置一些约束.

The LoginView class initialises both labels and should set some constraints.

class LoginView: UIView {

var usernameLabel: UILabel!
var passwordLabel: UILabel!


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

    setupLabels()
}

convenience init () {
    self.init(frame:CGRect.zero)
}

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

private func setupLabels(){
    //Init labels and set a simple text
    self.usernameLabel = UILabel()
    self.usernameLabel.text = "Username"
    self.passwordLabel = UILabel()
    self.passwordLabel.text = "Password"

    //Set constraints which aren't possible since there is no contentView, perhaps using the frame?
    }
}

这是无效的,因为视图的边界是0.但是,我找不到任何资源可以洞悉是否可行,因此我尝试了无效的方法.

This doesn't work since the view's bounds are 0. However I couldn't find any resource that gives insight in whether this is possible, so I tried my approach which didn't work.

如何将UIViewController的视图设置为以编程方式创建的自定义UIView?还是建议使用上面的代码段?

How you set the view of a UIViewController to a custom UIView which is made programmatically? Or is the above snippet recommended?

这是基于Jadar回答的有效解决方案:

class LoginViewController: UIViewController {

    override func loadView() {
        view = LoginView()
    }

    override func viewDidLoad() {
        super.viewDidLoad()        
    //  Do any additional setup after loading the view.

    }
}

class LoginView: UIView {

var usernameLabel: UILabel!
var passwordLabel: UILabel!

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

    self.usernameLabel = UILabel()
    self.usernameLabel.text = "Username"
    self.passwordLabel = UILabel()
    self.passwordLabel.text = "Password"

    addSubview(usernameLabel)
    addSubview(passwordLabel)

    if let superview = usernameLabel.superview{
        //Setting AutoLayout using SnapKit framework
        usernameLabel.snp.makeConstraints { (make) in
            make.center.equalTo(superview)
        }
    }
}

结果:

推荐答案

看来这里确实有两个问题.第一,以编程方式设置ViewController的最佳方法是什么.另外,如何以编程方式设置视图.

It looks there are really two questions here. One, what is the best way to programmatically set up a ViewController. The other, how to set up a View programmatically.

首先,使ViewController以编程方式使用其他UIView子类的最佳方法是在loadView方法中对其进行初始化和分配.根据Apple的文档:

First, The best way to have a ViewController programmatically use a different UIView subclass is to initialize and assign it in the loadView method. Per Apple's docs:

您可以重写此方法以便手动创建视图. 如果选择这样做,则将视图层次结构的根视图分配给 视图属性.您创建的视图应该是唯一的实例,并且 不应与任何其他视图控制器对象共享.你的 此方法的自定义实现不应调用super.

You can override this method in order to create your views manually. If you choose to do so, assign the root view of your view hierarchy to the view property. The views you create should be unique instances and should not be shared with any other view controller object. Your custom implementation of this method should not call super.

这看起来像这样:

class LoginViewController: UIViewController {    
    override func loadView() {
        // Do not call super!
        view = LoginView()
    }
}

通过这种方式,您不必处理大小,因为View Controller本身应该照顾它(就像它自己的UIView一样).

This way you shouldn't have to deal with sizing it, as the View Controller itself should take care of it (as it does with it's own UIView).

请记住,请勿调用super.loadView(),否则控制器将感到困惑.另外,第一次尝试此操作时,由于我忘记在我的App Delegate中调用window.makeKeyAndVisible(),因此出现了黑屏.在这种情况下,视图甚至从未添加到窗口层次结构中.您始终可以使用Xcode中的View Introspecter按钮查看正在发生的事情.

Remember, do not call super.loadView() or the controller will be confused. Also, the first time I tried this I got a black screen because I forgot to call window.makeKeyAndVisible() in my App Delegate. In this case the view was never even added to the window hierarchy. You can always use the view introspecter button in Xcode to see what's going on.

第二,您需要在UIView子类中调用self.addSubview(_:)才能使它们出现.将它们添加为子视图后,可以使用NSLayoutConstraint添加约束.

Second, you will need to call self.addSubview(_:) in your UIView subclass in order to have them appear. Once you add them as subviews, you can add constraints with NSLayoutConstraint.

private func setupLabels(){
    // Initialize labels and set their text
    usernameLabel = UILabel()
    usernameLabel.text = "Username"
    usernameLabel.translatesAutoresizingMaskIntoConstraints = false // Necessary because this view wasn't instantiated by IB
    addSubview(usernameLabel)

    passwordLabel = UILabel()
    passwordLabel.text = "Password"
    passwordLabel.translatesAutoresizingMaskIntoConstraints = false // Necessary because this view wasn't instantiated by IB
    addSubview(passwordLabel)

    NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[view]", options: [], metrics: nil, views: ["view":usernameLabel]))
    NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|-20-[view]", options: [], metrics: nil, views: ["view":passwordLabel]))

    NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[view]", options: [], metrics: nil, views: ["view":usernameLabel]))
    NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-20-[view]", options: [], metrics: nil, views: ["view":passwordLabel]))
}

有关用于创建约束的视觉格式语言的更多信息,请参见

For more info on the visual format language used to create the constraints, see the VFL Guide

这篇关于将UIViewController视图属性设置为不带故事板/笔尖的自定义UIView类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆