2015-09-07 10 views
6

私はを理解しようとしています autolayoutの制約。レイアウトは次のようになり、(溶液または議論なし)レイWチュートリアルチャレンジをする必要があり、以下: - 上下中央、幅と高さを持つ黄色のビューを作成IBでそれをやってコード内の制約は、有効にすることができない

desired layout

することは十分に簡単でしたマージンに水平に固定されています。そのビューの中に簡単な制約を付けてラベル、フィールド、ボタンを作成します。

私の最初の質問は次のとおりです。ラベルは固有のコンテンツのサイズを有し、そして他のすべてが黄色表示に固定されている場合、なぜ私は固定幅と高さを定義する必要がありますか?なぜサブビューの本質的な内容から幅と高さを推測しないのでしょうか?

上を移動すると、コードでこのレイアウトを再作成しようとは私にエラーを与えていた。

Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with items <UILabel: 0x7a961d60; frame = (0 0; 0 0); text = 'Password:'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7a961e40>> and <UIView: 0x7a96b6f0; frame = (0 0; 0 0); layer = <CALayer: 0x7a96b880>> because they have no common ancestor. Does the constraint reference items in different view hierarchies? That's illegal.'

2番目の質問:どのようなこれらの層があり、そしてすべての私の見解はheirachyである - スーパーは、黄色のビューが含まれている含まれていますテキストのラベルとフィールド。

多くの苦痛の後、私はIBで行われた制約を正確に再現しようとしましたが、これは次のエラーだけを追加しました: 同時に制約を満たすことができません。

(
    "<NSLayoutConstraint:0x7ac57370 H:[UIView:0x7a96b6f0(0)]>", 
    "<NSLayoutConstraint:0x7ac57400 H:|-(8)-[UILabel:0x7a96bb50'Username:'] (Names: '|':UIView:0x7a96b6f0)>", 
    "<NSLayoutConstraint:0x7ac57430 UILabel:0x7a96bb50'Username:'.trailing == UITextField:0x7a961020.leading + 8>", 
    "<NSLayoutConstraint:0x7ac57520 UITextField:0x7a961020.trailing == UIView:0x7a96b6f0.trailing - 8>") 

最終的な質問:どのようなビューがビューであるかを知るにはどうすればいいですか0x7aetc?私のコードでこの制約はどこにありますか?残りはok(?)に見えます。

いくつかの基本レベルで何か非常に間違っている必要があります。

import UIKit 

class ViewController: UIViewController { 

    let centerView = UIView() 
    let usernameLabel = UILabel() 
    let passwordLabel = UILabel() 
    let usernameField = UITextField() 
    let passwordField = UITextField() 
    let submitButton = UIButton() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     centerView.backgroundColor = UIColor.yellowColor() 
     usernameLabel.text = "Username:" 
     passwordLabel.text = "Password:" 
     usernameField.borderStyle = .RoundedRect 
     passwordField.borderStyle = .RoundedRect 
     submitButton.setTitle("Submit!", forState: .Normal) 
     submitButton.setTitleColor(UIColor.blackColor(), forState: .Normal) 
     submitButton.setTitleColor(UIColor.blueColor(), forState: .Highlighted) 

     view.addSubview(centerView) 
     self.centerView.addSubview(usernameField) 
     self.centerView.addSubview(passwordField) 
     self.centerView.addSubview(usernameLabel) 
     self.centerView.addSubview(submitButton) 

     let constraintCenterViewHeight = NSLayoutConstraint(item: centerView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 0) 
     let constraintCenterViewWidth = NSLayoutConstraint(item: centerView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 0) 

     let constraintCenterViewCenterX = NSLayoutConstraint(item: centerView, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1.0, constant: 0) 
     let constraintCenterViewCenterY = NSLayoutConstraint(item: centerView, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1.0, constant: 0) 

     let constraintUsernameLabelHLeading = NSLayoutConstraint(item: usernameLabel, attribute: .Leading, relatedBy: .Equal, toItem: centerView, attribute: .Leading, multiplier: 1.0, constant: 8) 
     let constraintUsernameLabelHTrailing = NSLayoutConstraint(item: usernameLabel, attribute: .Trailing, relatedBy: .Equal, toItem: usernameField, attribute: .Leading, multiplier: 1.0, constant: 8) 
     let constraintUsernameLabelAlignBottom = NSLayoutConstraint(item: usernameLabel, attribute: .Bottom, relatedBy: .Equal, toItem: usernameField, attribute: .Bottom, multiplier: 1.0, constant: 0) 

     let constraintUsernameFieldVTop = NSLayoutConstraint(item: usernameField, attribute: .Top, relatedBy: .Equal, toItem: centerView, attribute: .Top, multiplier: 1.0, constant: 8) 
     let constraintUsernameFieldHTrailing = NSLayoutConstraint(item: usernameField, attribute: .Trailing, relatedBy: .Equal, toItem: centerView, attribute: .Trailing, multiplier: 1.0, constant: -8) 
     let constraintUsernameFieldVBottom = NSLayoutConstraint(item: usernameField, attribute: .Bottom, relatedBy: .Equal, toItem: passwordField, attribute: .Top, multiplier: 1.0, constant: 8) 

     let constraintPasswordLabelHLeading = NSLayoutConstraint(item: passwordLabel, attribute: .Leading, relatedBy: .Equal, toItem: centerView, attribute: .Leading, multiplier: 1.0, constant: 8) 
     let constraintPasswordLabelHTrailing = NSLayoutConstraint(item: passwordLabel, attribute: .Trailing, relatedBy: .Equal, toItem: passwordField, attribute: .Leading, multiplier: 1.0, constant: 8) 
     let constraintPasswordLabelAlignBottom = NSLayoutConstraint(item: passwordLabel, attribute: .Bottom, relatedBy: .Equal, toItem: passwordField, attribute: .Bottom, multiplier: 1.0, constant: 0) 

     let constraintPasswordFieldHTrailing = NSLayoutConstraint(item: passwordField, attribute: .Trailing, relatedBy: .Equal, toItem: centerView, attribute: .Trailing, multiplier: 1.0, constant: -8) 

     centerView.setTranslatesAutoresizingMaskIntoConstraints(false) 
     usernameLabel.setTranslatesAutoresizingMaskIntoConstraints(false) 
     usernameField.setTranslatesAutoresizingMaskIntoConstraints(false) 
     passwordField.setTranslatesAutoresizingMaskIntoConstraints(false) 
     passwordLabel.setTranslatesAutoresizingMaskIntoConstraints(false) 
     // submitButton.setTranslatesAutoresizingMaskIntoConstraints(false) 

     NSLayoutConstraint.activateConstraints([constraintCenterViewHeight, constraintCenterViewWidth, constraintCenterViewCenterX, constraintCenterViewCenterY, constraintUsernameLabelHLeading, 
      constraintUsernameLabelHTrailing, constraintUsernameLabelAlignBottom, constraintUsernameFieldVTop, constraintUsernameFieldHTrailing, constraintUsernameFieldVBottom, constraintPasswordLabelHLeading, constraintPasswordLabelHTrailing, constraintPasswordLabelAlignBottom, constraintPasswordFieldHTrailing]) 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 


} 

答えて

15

My first question is: if the labels have an intrinsic content size, and everything else is pinned to the yellow view, then why do I need to define a fixed width and height? Why wouldn't it infer the width and height from the intrinsic content of its subviews?

usernamepasswordフィールドは幅を持っていない:

は、ここに私のコードです。それらは、centerViewの左端と右端のラベルに固定されて、幅を取得します。これらのフィールドに幅を与えるための制約を追加した場合、centerViewはその内容から幅を決定できます。


Moving on and trying to recreate this layout in code was giving me an error: Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with items > and > because they have no common ancestor. Does the constraint reference items in different view hierarchies? That's illegal.'

あなたの最初の問題は、あなたがサブビューとしてpasswordLabelを追加しなかったことである:あなたのエラーを与えていたされているもの

self.centerView.addSubview(passwordLabel) 

passwordLabelはビュー階層に含まれていないため、自動レイアウトはcenterViewでそれを制約する方法を知らなかった。

2番目の問題は、centerViewwidthheight0に設定したことです。試してみてください100300のような大きな値:

let constraintCenterViewHeight = NSLayoutConstraint(item: centerView, attribute: .Height, 
    relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, 
    constant: 100) 

let constraintCenterViewWidth = NSLayoutConstraint(item: centerView, attribute: .Width, 
    relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, 
    constant: 300) 

あなたの第三の問題は、あなたの定数の一部が負である必要があることです。

// changed to -8 
let constraintUsernameLabelHTrailing = NSLayoutConstraint(item: usernameLabel, 
    attribute: .Trailing, relatedBy: .Equal, toItem: usernameField, 
    attribute: .Leading, multiplier: 1.0, constant: -8) 

// changed to -8 
let constraintUsernameFieldVBottom = NSLayoutConstraint(item: usernameField, 
    attribute: .Bottom, relatedBy: .Equal, toItem: passwordField, 
    attribute: .Top, multiplier: 1.0, constant: -8) 

// changed to -8 
let constraintPasswordLabelHTrailing = NSLayoutConstraint(item: passwordLabel, 
    attribute: .Trailing, relatedBy: .Equal, toItem: passwordField, 
    attribute: .Leading, multiplier: 1.0, constant: -8) 
+0

私はこのコードを数日間見て、見逃したサブビューや幅と高さを0として見たことはありません! ああ、(私がそれを得ていないと書いていたように)私の鈍い古い脳は、usernameLabelの後端がusernameFieldのリーディングエッジに対して、Y軸または水平軸に沿ってさらに8点あると考えました。しかし、それはただのばかげたミスです。私はusernameLabelの後端をusernameFieldの前縁8点にYまたは水平軸に沿って戻したい。 非常に残念ですが、あなたがこれを指摘してくれて非常に感謝しています。あなたがそれを理解すれば、このことが働くことを知ることは素晴らしいことです。 – DrWhat

4

私は同じエラーを得たが、それは起こった理由は違うものでした:私は前に私のスーパーを基準にしているので、私はエラーを得た

私はそのスーパーにビューを追加しました。 < - あなたのコードを書くことはと異なり、view.addSubview(stackView)を含まないものとは異なります。ビューにはスーパービューとの関係が定義されていないため、両方とも同じエラーが生成されます。

私のコードでは、ラインAA、ビューにスーパービューにビューを追加する前に、ラインB1、B2が起きています。

これは私のコードです:

class ViewController: UIViewController { 

    var label = UILabel() 
    var button = UIButton() 
    var stackView = UIStackView() 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     view.backgroundColor = UIColor.cyan 
     navigationItem.title = "VCTitle" 
     setupUI() 
    } 

    private func setupUI(){ 

     label.backgroundColor = UIColor.blue 
     label.heightAnchor.constraint(equalToConstant: 50).isActive = true 
     label.widthAnchor.constraint(equalToConstant: 80).isActive = true 

     button.backgroundColor = UIColor.purple 
     button.heightAnchor.constraint(equalToConstant: 30).isActive = true 
     button.widthAnchor.constraint(equalToConstant: 10).isActive = true 

     setupStackView() 

     stackView.addArrangedSubview(label) 
     stackView.addArrangedSubview(button) 
     stackView.translatesAutoresizingMaskIntoConstraints = false 
     view.addSubview(stackView) // AA 


    } 

    private func setupStackView(){ 

     stackView.axis = UILayoutConstraintAxis.vertical 
     stackView.distribution = UIStackViewDistribution.equalSpacing 
     stackView.alignment = UIStackViewAlignment.center 
     stackView.spacing = 15 

     stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true // B1 
     stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true // B2 

    } 


} 

それを行うための正しい方法は、どこにでも後の線AAにラインB1、B2を移動することです。

class ViewController: UIViewController { 

    var label = UILabel() 
    var button = UIButton() 
    var stackView = UIStackView() 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     view.backgroundColor = UIColor.cyan 
     navigationItem.title = "VCTitle" 
     setupUI() 
    } 

    private func setupUI(){ 

     label.backgroundColor = UIColor.blue 
     label.heightAnchor.constraint(equalToConstant: 50).isActive = true 
     label.widthAnchor.constraint(equalToConstant: 80).isActive = true 

     button.backgroundColor = UIColor.purple 
     button.heightAnchor.constraint(equalToConstant: 30).isActive = true 
     button.widthAnchor.constraint(equalToConstant: 10).isActive = true 

     setupStackView() 

     stackView.addArrangedSubview(label) 
     stackView.addArrangedSubview(button) 
     stackView.translatesAutoresizingMaskIntoConstraints = false 
     view.addSubview(stackView) //AA 

     // The 2 lines below are now in the right place. 
     stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true // B1 
     stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true // B2 


    } 

    private func setupStackView(){ 

     stackView.axis = UILayoutConstraintAxis.vertical 
     stackView.distribution = UIStackViewDistribution.equalSpacing 
     stackView.alignment = UIStackViewAlignment.center 
     stackView.spacing = 15 

    } 
} 
関連する問題