![](/img/trans.png)
[英]Add a subview to a custom class UIViewController that loads from nib, in Storyboard
[英]Set UIViewController view property to custom UIView class without storyboard / nib
我有一個名為LoginViewController
的UIViewController
。 我想在一個名為LoginView
的自定義UIView
類中以編程方式完全構建LoginViewController
的視圖,而不是在我的LoginViewController
中構建所有元素。 這樣,我就可以防止Controller類(MVC)中的“查看”代碼。
在下面的代碼中,我將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) } } }
結果:
看起來這里確實有兩個問題。 第一,以編程方式設置ViewController的最佳方法是什么。 另外,如何以編程方式設置視圖。
首先,讓ViewController以編程方式使用其他UIView子類的最佳方法是在loadView
方法中對其進行初始化和分配。 根據Apple的文檔 :
您可以覆蓋此方法,以便手動創建視圖。 如果選擇這樣做,請將視圖層次結構的根視圖分配給view屬性。 您創建的視圖應該是唯一的實例,並且不應與任何其他視圖控制器對象共享。 您對此方法的自定義實現不應調用super。
看起來像這樣:
class LoginViewController: UIViewController {
override func loadView() {
// Do not call super!
view = LoginView()
}
}
這樣,您就不必處理它的大小,因為View Controller本身應該照顧它(就像它自己的UIView一樣)。
請記住,不要調用super.loadView()
否則控制器會感到困惑。 另外,第一次嘗試此操作時,我出現黑屏,因為我忘記在我的應用程序委托中調用window.makeKeyAndVisible()
。 在這種情況下,視圖甚至從未添加到窗口層次結構中。 您始終可以使用Xcode中的view 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指南》。
重寫layoutSubviews
方法以更新自定義視圖內子視圖的框架。
而且永遠不要調用super.loadView()
。 記錄了loadView
方法。
您應該在已經加載LoginViewController的布局約束時加載自定義視圖,請嘗試以下操作:
override func viewDidLoad() {
super.viewDidLoad()
let newView = LoginView(frame: view.bounds)
view.addSubview(newView)
}
在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具有一個frame,您可以通過提供框架來通過代碼設置所有視圖。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.