2016-12-31 7 views
4

UIViewControllerLoginViewControllerといいます。私はそのLoginViewControllerのビューを、LoginViewController内のすべての要素を構築する代わりに、のカスタムUIViewクラスをLoginViewと呼びます。このようにして、コントローラクラス(MVC)の「表示」コードを禁止します。ストーリーボード/ペンなしのUIViewControllerビュープロパティをカスタムUIViewクラスに設定します

I以下のコードで

は簡単にするためだけLoginViewクラスは両方のラベルを初期化し、いくつかの制約を設定する必要があります2 UILabels

class LoginViewController: UIViewController { 

override func loadView() { 
    super.loadView() 

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

が含まれている私のLoginViewに私のLoginViewControllerのビューを設定しています。

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

結果:

Result

+1

コードを見るには、ビューコントローラの正しいではありません。 viewDidLoadでself.viewを設定しないでください。もともとのようにloadViewで行います。 – rmaddy

+0

フィードバックいただきありがとうございます! @rmaddy – Hapeki

答えて

3

それは二つの質問はここに実際にそこにあるに見えます。 1つは、プログラムでViewControllerを設定する最適な方法は何ですか。もう1つは、プログラムでビューを設定する方法です。

最初に、ViewControllerに別のUIViewサブクラスをプログラムで使用させる最良の方法は、loadViewメソッドで初期化して割り当てることです。 Appleごとdocs

手動でビューを作成するには、このメソッドをオーバーライドできます。 これを行う場合は、ビュー階層のルートビューを viewプロパティに割り当てます。作成するビューは一意のインスタンスで、 は他のView Controllerオブジェクトと共有しないでください。 このメソッドのカスタム実装では、superを呼び出すべきではありません。

これは、このようなものになります。

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

あなたがそれをサイズ変更に対処する必要はありません。この方法で、それはそれ自身と同じように、それ自体が(それの世話をする必要がありますビューコントローラとしてのUIView)。

super.loadView()に電話しないでください。そうしないと、コントローラが混乱します。また、初めて私がこれを試したときに私はwindow.makeKeyAndVisible()私のApp Delegateに電話するのを忘れていたので、黒い画面が表示されました。この場合、ビューはウィンドウ階層に追加されませんでした。 Xcodeのビューイントロスペクサーボタンを使って、何が起きているのかをいつでも確認できます。

第2に、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

+0

これは正解です。 – matt

+0

これは全く質問に答えません。 OPはもともとこれをやっていた。それは問題ではありませんでした。問題は、カスタムビューの実装であり、ビューコントローラでのビューの作成方法ではありません。 – rmaddy

+0

実際、私たちは両方ともOPの質問を誤解していると思います。本当の問題のように聞こえるのは、ラベルが表示されていないということです。しかし、それは1、彼はサブビューとしてそれらを追加することは決してありません。コントローラとレイアウトの両方の質問を反映するように答えを更新しました。 – Jadar

2

内部サブビューのフレームを更新するために、layoutSubviewsメソッドをオーバーライドしますあなたのカスタムビュー。

super.loadView()には絶対に電話しないでください。これは、loadViewメソッドで文書化されています。

+0

あなたの返事ありがとうございます。私のフレームがCGRect.zeroでも、layoutSubviewsでAutoLayout(SnapKit)を使ってフレームを更新する方法はありますか?私はパスワードのラベルセンターをスーパービューにする方法を見つけることができません。何もないようですから? – Hapeki

+0

自動レイアウトを使用する場合は、初期フレームをゼロ以外のフレームに設定し、サブビューを初期作成するときに自動レイアウトを設定します。そして、 'layoutSubviews'を実装する必要はありません。 – rmaddy

+0

この回答は、OPが彼/彼女の問題を解決するのに役立つ適切な情報を提供していません。 – Jadar

2

あなたがLoginViewControllerのレイアウト制約がすでにロードされているカスタムビューをロードする必要があり、これを試してみてください。

override func viewDidLoad() { 
     super.viewDidLoad() 
     let newView = LoginView(frame: view.bounds) 
     view.addSubview(newView) 
    } 
+0

返信いただきありがとうございます。私はあなたの答えに基づいて潜在的な解決策で自分の投稿を編集しました。この解決策がコミュニティによって有効な解決策として受け入れられた場合、私はこの回答を受け入れたものとしてマークします。 nibを使用せずに、ビュー階層をプログラムで作成するためにloadViewを実装していますが、ビューを設定するためにviewDidLoadを呼び出すことは良いことです。 viewDidLoadを実装して、ビューをロードした後、通常はペン先から追加の設定を行います。 – Hapeki

+2

これは可能な解決策の1つですが、loadViewを使用する元のソリューションは、ビューコントローラのビューをカスタムビューに設定する適切な場所です。 – rmaddy

+0

loadViewを使用する場合は、現在のビューコントローラ以外のフレームでカスタムビューを初期化する必要があります。これはまだロードされていないため、LoginViewのフレームに 'UIScreen.main.bounds'を設定できます。私はただ私に知らせるための例が必要です。 – DariusV

関連する問題