2016-04-17 5 views
3

になりましたプログラムで「スコアページ」を生成しようとしていますが、各属性のスコアに対してUILabelとUISliderがあります。固定数の属性がないので、私はこれをプログラムで行います(ストーリーボードとは対照的に)NSLayoutConstraintsに問題があり、プログラムで自動レイアウトを使用すると、UIViewsが(0,0)

私の考えは、各属性ごとにUIViewを作成し、 UIViewにUILabelと1つのUISliderを追加し、その後に制約を設定します。

しかし、私は制約を適切に設定できないという問題に遭遇しています。あるいは、そのようなことを経験していないために逃したかもしれない別の大きなエラーです。その結果、すべてのUIViewは画面の左上(0,0)に固定され、互いに重なり合って表示されます。ここで

は、これまでの私のコードです:

func addLabels(attributesArray: [String], testResultsDictionary: [String:Double]){ 
    var viewsDictionary = [String:AnyObject]() 
    //let numberOfAttributes = attributesArray.count //(vestigial, please ignore) 
    let sliderHeight = Double(20) 
    let sliderWidth = Double(UIScreen.mainScreen().bounds.size.width)*0.70 // 70% across screen 
    let labelToSliderDistance = Float(10) 
    let sliderToNextLabelDistance = Float(30) 
    let edgeHeightConstraint = Float(UIScreen.mainScreen().bounds.size.height)*0.10 // 10% of screen height 

    for attribute in attributesArray { 

     let attributeView = UIView(frame: UIScreen.mainScreen().bounds) 
     attributeView.backgroundColor = UIColor.blueColor() 
     attributeView.translatesAutoresizingMaskIntoConstraints = false 
     attributeView.frame.size = CGSize(width: Double(UIScreen.mainScreen().bounds.size.width)*0.80, height: Double(80)) 
     self.view.addSubview(attributeView) 

     var attributeViewsDictionary = [String:AnyObject]() 
     let attributeIndex = attributesArray.indexOf(attribute)! as Int 

     let attributeLabel = UILabel() 
     attributeLabel.translatesAutoresizingMaskIntoConstraints = false 
     attributeLabel.text = attribute.stringByReplacingOccurrencesOfString("_", withString: " ") 
     attributeLabel.sizeToFit() 

     let attributeSlider = UISlider() 
     attributeSlider.translatesAutoresizingMaskIntoConstraints = false 
     attributeSlider.setThumbImage(UIImage(), forState: .Normal) 
     attributeSlider.frame.size = CGSize(width: sliderWidth, height: sliderHeight) 
     attributeSlider.userInteractionEnabled = false 

     if let sliderValue = testResultsDictionary[attribute] { 
      attributeSlider.value = Float(sliderValue) 
     } 
     else { 
      attributeSlider.value = 0 
     } 

     attributeView.addSubview(attributeLabel) 
     attributeView.addSubview(attributeSlider) 

     //attributeView.sizeToFit() 

     attributeViewsDictionary["Label"] = attributeLabel 
     attributeViewsDictionary["Slider"] = attributeSlider 

     viewsDictionary[attribute] = attributeView 
     print(viewsDictionary) 

     let control_constraint_H = NSLayoutConstraint.constraintsWithVisualFormat("H:|-[\(attribute)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDictionary) 
     var control_constraint_V = [NSLayoutConstraint]() 
     if attributeIndex == 0 { 
      control_constraint_V = NSLayoutConstraint.constraintsWithVisualFormat("V:|-\(edgeHeightConstraint)-[\(attribute)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDictionary) 
     } 
     else if attributeIndex == attributesArray.indexOf(attributesArray.last!){ 
      control_constraint_V = NSLayoutConstraint.constraintsWithVisualFormat("V:[\(attribute)]-\(edgeHeightConstraint)-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDictionary) 
     } 
     else { 
      control_constraint_V = NSLayoutConstraint.constraintsWithVisualFormat("V:[\(attributesArray[attributeIndex-1])]-\(sliderToNextLabelDistance)-[\(attribute)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDictionary) 
     } 

     self.view.addConstraints(control_constraint_H) 
     self.view.addConstraints(control_constraint_V) 

     let interAttributeConstraint_V = NSLayoutConstraint.constraintsWithVisualFormat("V:[Label]-\(labelToSliderDistance)-[Slider]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: attributeViewsDictionary) 
     //let interAttributeConstraint_H = NSLayoutConstraint.constraintsWithVisualFormat("H:[Label]-5-[Slider]", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: attributeViewsDictionary) 

     attributeView.addConstraints(interAttributeConstraint_V) 
     //attributeView.addConstraints(interAttributeConstraint_H) 
     //attributeView.sizeToFit() 
    } 
} 

エクストラ注: - :[ "幸福"、 "創造"、 "Tendency_To_Slip"]

  • コード attributeArrayは次のようになりますそれはプロトタイプであるので、非常に乱雑で不必要に長いですので、ごめんなさい!それに耐えてください!

この質問を読んでいただきありがとうございます。 :D

+0

解決済み!各要素のサイズに制約を与えることにも欠けていました(attributeView、attributeLabel、attributeSlider)。この他の質問は、この問題の解決にも私を助けました! http://stackoverflow.com/questions/26180822/swift-adding-constraints-programmatically –

答えて

1

問題は、これらのビューの制約が完全に定義されていないことです(特に、垂直方向の制約がありません)。自動レイアウトを使用すると、すべてのframe値は破棄され、自動レイアウトプロセスによって再計算されるため、様々なビューのをframeのさまざまなビューに設定しようとしましたが、これは無駄です。代わりに、ビューの次元が完全に制約によって完全に定義されていることを確認してください。例えば

let spacing: CGFloat = 10 

func addLabels(attributesArray: [String], testResultsDictionary: [String: Float]) { 
    var previousContainer: UIView? // rather than using the index to look up the view for the previous container, just have a variable to keep track of the previous one for you. 

    for attribute in attributesArray { 
     let container = UIView() 
     container.backgroundColor = UIColor.lightGrayColor() // just so I can see it 
     container.translatesAutoresizingMaskIntoConstraints = false 
     view.addSubview(container) 

     // set top anchor for container to superview if no previous container, otherwise link it to the previous container 

     if previousContainer == nil { 
      container.topAnchor.constraintEqualToAnchor(view.topAnchor, constant: spacing).active = true 
     } else { 
      container.topAnchor.constraintEqualToAnchor(previousContainer!.bottomAnchor, constant: spacing).active = true 
     } 
     previousContainer = container 

     // set leading/trailing constraints for container to superview 

     NSLayoutConstraint.activateConstraints([ 
      container.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor, constant: spacing), 
      view.trailingAnchor.constraintEqualToAnchor(container.trailingAnchor, constant: spacing), 
     ]) 

     // create label 

     let label = UILabel() 
     label.translatesAutoresizingMaskIntoConstraints = false 
     label.text = attribute 
     container.addSubview(label) 

     // create slider 

     let slider = UISlider() 
     slider.translatesAutoresizingMaskIntoConstraints = false 
     slider.value = testResultsDictionary[attribute]! 
     container.addSubview(slider) 

     // constraints for label and slider 

     NSLayoutConstraint.activateConstraints([ 
      label.topAnchor.constraintEqualToAnchor(container.topAnchor, constant: spacing), 
      slider.topAnchor.constraintEqualToAnchor(label.bottomAnchor, constant: spacing), 
      container.bottomAnchor.constraintEqualToAnchor(slider.bottomAnchor, constant: spacing), 

      label.leadingAnchor.constraintEqualToAnchor(container.leadingAnchor, constant: spacing), 
      slider.leadingAnchor.constraintEqualToAnchor(container.leadingAnchor, constant: spacing), 

      container.trailingAnchor.constraintEqualToAnchor(label.trailingAnchor, constant: spacing), 
      container.trailingAnchor.constraintEqualToAnchor(slider.trailingAnchor, constant: spacing) 
     ]) 
    } 
} 

は今、私は(それは表現力と簡潔である)制約を定義するためのiOS 9構文を使用することが起こるが、あなたがしたい場合は、あなたがそれを行うことができます/ VFLを使用する必要があり、あまりにも。あいまいに定義されている同等の制約セット(上、下、上、下)を定義するようにしてください。また、これらのコンテナのビューのサイズをハードコーディングするのではなく、サブビューのサイズから推測させて、コンテナのビューがそれに応じてサイズ変更されることにも注意してください。

私はこのUIを見ているので、これらの制約をすべて定義する必要がなくなり、シナリオを適切に処理することができますそこにはスクロールの振る舞いを楽しんでほしいものがたくさんあります。または、これらが常に1つの画面に収まることが分かっていた場合は、UIStackViewを使用します。しかし、あなたが制約をもってそれをしたいのであれば、上記のようなことをするかもしれません。

+0

「テーブル」形式で情報を表示するさまざまな方法を理解していただきありがとうございます。 :D iOS 9構文は、ショートカットのようには思えないが、VFLは「汚れた」方法であり、間違いが起こりやすく(私が経験したものから)選びにくい。 –