我有UIViewController
名为LoginViewController
。我想在名为LoginViewController
的自定义UIView
类中构建LoginView
完全以编程方式的视图,而不是构建LoginViewController
中的所有元素。这样我就阻止了Controller类(MVC)中的“View”代码。
在下面的代码中,我将LoginViewController
的视图设置为LoginView
,为简单起见,只包含2 UILabels
class LoginViewController: UIViewController {
override func loadView() {
super.loadView()
self.view = LoginView(frame: CGRect.zero)
}
LoginView类初始化两个标签,并应设置一些约束。
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.但是我找不到任何能够深入了解这是否可行的资源,所以我尝试了我的方法,但是没有用。
如何将UIViewController的视图设置为以编程方式创建的自定义UIView?或者上面的片段是推荐的吗?
这是基于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) } } }
结果:
{{3}}
答案 0 :(得分:12)
看来这里真的有两个问题。一,以编程方式设置ViewController的最佳方法是什么。另一种,如何以编程方式设置View。
首先,以编程方式使用不同UIView子类的ViewController的最佳方法是在loadView
方法中初始化并分配它。根据Apple的docs:
您可以覆盖此方法以手动创建视图。 如果选择这样做,请将视图层次结构的根视图指定给 视图属性。您创建的视图应该是唯一的实例 不应与任何其他视图控制器对象共享。您的 这种方法的自定义实现不应该调用super。
这看起来像这样:
class LoginViewController: UIViewController {
override func loadView() {
// Do not call super!
view = LoginView()
}
}
这样你就不必处理它的大小调整,因为View Controller本身应该处理它(就像它使用它自己的UIView一样)。
请记住,不要拨打super.loadView()
或控制器会混淆。此外,我第一次尝试这个时,我得到了一个黑屏,因为我忘了在我的App Delegate中拨打window.makeKeyAndVisible()
。在这种情况下,视图从未添加到窗口层次结构中。您始终可以使用Xcode中的视图introspecter按钮查看正在进行的操作。
其次,您需要在UIView子类中调用self.addSubview(_:)
才能显示它们。将它们添加为子视图后,您可以使用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]))
}
有关用于创建约束的可视格式语言的详细信息,请参阅VFL Guide
答案 1 :(得分:2)
重写layoutSubviews
方法以更新自定义视图中的子视图的框架。
永远不要致电super.loadView()
。这是针对loadView
方法记录的。
答案 2 :(得分:2)
你应该在加载了LoginViewController的布局约束时加载自定义视图,试试这个:
override func viewDidLoad() {
super.viewDidLoad()
let newView = LoginView(frame: view.bounds)
view.addSubview(newView)
}
答案 3 :(得分:0)
在Viewcontroller的loadView方法中执行以下操作:
class LoginViewController: UIViewController {
override func loadView() {
super.view = LoginView()
}
}
在你的UIView自定义课程中执行以下操作:
class LoginView: UIView {
convenience init() {
self.init(frame: UIScreen.main.bounds)
setupLabels()
}
}
现在您的UIView有一个框架,您可以通过提供框架来设置所有视图。