31

私は最近、Swift を使用した iOS 開発に再び飛び込み始め、現在はカスタム UIControl を検討しています。レイアウトと柔軟性のために、このカスタム ビューは StackView を使用して構築されています。

達成したいこと...

...基本的には、スタックビューをストーリーボードに直接ドラッグしたときに通常持っているのと同じ機能を単純に持つことです-問題なく収まるようにサイズが変更されます。これは基本的に、自動サイズ設定のテーブルビュー セルと同じです。

ショーケース

CustomView を単純な例に減らすことができます。これは、3 つのラベルが , に設定されたStackViewAlignmentです。StackView は、左、右、および上部のレイアウト ガイド (または末尾、先頭、および上部) に固定されます。これは、XIB から読み込まれた CustomView を使用して簡単に再作成でき、同じパラメーターを持つ CustomView に変換されます。両方をスクリーンショットとして添付しました。CenterDistribution Equal Centering

シンプルな StackView のスクリーンショット

CustomView のスクリーンショット

XIB ファイルを読み込んでセットアップします。

import UIKit

@IBDesignable
class CustomView: UIView {

    // loaded from NIB
    private weak var view: UIView!

    convenience init() {
        self.init(frame: CGRect())
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.loadNib()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.loadNib()
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        // we need to adjust the frame of the subview to no longer match the size used
        // in the XIB file BUT the actual frame we got assinged from the superview
        self.view.frame = bounds
    }

    private func loadNib ()  {
        self.view = Bundle (for: type(of: self)).loadNibNamed(
            "CustomView", owner: self, options: nil)! [0] as! UIView
        self.addSubview(self.view)
    }
}

ここでわかるのは、XIB ファイルをロードし、レイアウトのサブビューをオーバーライドして、フレームを実際のビューに適応させるだけです。

質問

したがって、私の質問は、これが通常どのようにアプローチされるかに関連しています。私の StackView のラベルには固有のコンテンツ サイズがあります。つまり、通常、StackView は文句を言わずにラベルの高さに適応します - ストーリーボードで設計する場合。ただし、すべてを XIB に入れてレイアウトをそのままにしておくと、そうではありません。ビューがスクリーンショットのように 3 つの方法 (上、先頭、末尾) に固定されている場合、IB は不明な高さについて文句を言います。

私は Auto-Layout Guide を読み、WWDC ビデオの "Mysteries of AutoLayout" を見ましたが、このトピックはまだ私にとってまったく新しいものであり、まだ正しいアプローチができていないと思います。だからここは私が助けを必要としているところです

(1) 制約を設定して無効にする必要がありtranslatesAutoresizingMaskIntoConstraintsますか?

私が最初にできることとすべきことは、 translatesAutoresizingMaskIntoConstraints false自動生成された制約を取得しないように設定し、独自の制約を定義することです。したがって、次のように変更できますloadNib

private func loadNib ()  {
    self.view = Bundle (for: type(of: self)).loadNibNamed(
        "CustomView", owner: self, options: nil)! [0] as! UIView
    self.view.translatesAutoresizingMaskIntoConstraints = false
    self.addSubview(self.view)

    self.addConstraint(NSLayoutConstraint (
        item: self
        , attribute: .bottom
        , relatedBy: .equal
        , toItem: self.view
        , attribute: .bottom
        , multiplier: 1.0
        , constant: 0))

    self.addConstraint(NSLayoutConstraint (
        item: self
        , attribute: .top
        , relatedBy: .equal
        , toItem: self.view
        , attribute: .top
        , multiplier: 1.0
        , constant: 0))

    self.addConstraint(NSLayoutConstraint (
        item: self.view
        , attribute: .leading
        , relatedBy: .equal
        , toItem: self
        , attribute: .leading
        , multiplier: 1.0
        , constant: 0))

    self.addConstraint(NSLayoutConstraint (
        item: self.view
        , attribute: .trailing
        , relatedBy: .equal
        , toItem: self
        , attribute: .trailing
        , multiplier: 1.0
        , constant: 0))
}

基本的に、ストーリーボードの UIView の全幅に収まるようにビューを引き延ばし、StackView の上下から上下に制限しました。

これを使用するとXCode 8がクラッシュするという問題がたくさんあったので、どうすればよいかわかりません。

(2)またはオーバーライドする必要がありますintrinsicContentSizeか?

intrinsicContentSizeまた、すべての高さを確認してオーバーライドしarrangedSubviews、最も高いものを取得して、ビューの高さをそれに設定することもできます。

override var intrinsicContentSize: CGSize {
    var size = CGSize.zero

    for (_ , aSubView) in (self.view as! UIStackView).arrangedSubviews.enumerated() {
        let subViewHeight = aSubView.intrinsicContentSize.height
        if  subViewHeight > size.height {
            size.height = aSubView.intrinsicContentSize.height
        }
    }

    // add some padding
    size.height += 0
    size.width = UIViewNoIntrinsicMetric
    return size
}

これにより確かに柔軟性が向上しますが、固有のコンテンツサイズを無効にする必要があるため、動的タイプや、避けたい他の多くのものを確認してください。

(3)「提案された」方法でXIBをロードしていますか?

または、より良い方法がありUINib.instantiateますか? 私は本当にそれを行うためのベストプラクティスの方法を見つけることができませんでした.

(4) そもそもなぜこれをしなければならないのですか?

ほんとに?なんで?StackView を CustomView に移動しただけです。では、StackView が適応を停止したのはなぜですか? なぜ上部と下部の制約を設定する必要があるのでしょうか?

これまでのところ最も役に立ったのは、https://stackoverflow.com/a/24441368のキーフレーズです。

「一般に、自動レイアウトはトップダウン方式で実行されます。つまり、親ビューのレイアウトが最初に実行され、次に子ビューのレイアウトが実行されます。」

..しかし、私はそれについて本当によくわかりません。

(5) コードに制約を追加する必要があるのはなぜですか?

無効にするとtranslatesAutoresizingMaskIntoConstraints、IBのテーブルビューセルのような制約を設定できませんか? これは常に label.top = top のようなものに変換されるため、サイズ/高さを継承する StackView の代わりにラベルが引き伸ばされます。また、XIBファイルのIBのコンテナビューにStackViewを実際に固定することはできません。

誰かが私を助けてくれることを願っています。乾杯!

4

1 に答える 1