5

ソース コードを試してみたい場合 (大歓迎です)、私のBitbucketリポジトリをご覧ください。

設定のリストを表示するポップオーバー ダイアログがあります。これらの設定は、複数の UITableViews 内にリストされています。UITableViews は、全体的な設定ビューが既にスクロール可能であるため、スクロール可能であってはなりません。さらに、ポップオーバー ダイアログは垂直方向に必要なだけ画面を占有しますが、水平方向には圧縮されます。

そこで、次のような構造を考えました。

UIView => MySettingsViewController
- UIScrollView
  - UIView (Content View)
    - Container View1
      - UITableView (embedded) => MyTableViewController
    - Container View2
      - UITableView (embedded)

構造は Interface Builder を介して組み立てられ、サイズ設定には Autolayout が使用されます。

スクロール ビュー、コンテンツ ビュー (1 つだけから始めました)、およびコンテナー ビューの両方をそれぞれのスーパービュー (またはレイアウト ガイド) に持っています。次の方法でコンテンツ ビューのサイズを制限しました。

contentView.width == (topmost) UIView.width
contentView.height == 200 // removed at build time

さらに、テーブル ビューのサイズをそのコンテンツ サイズに設定しました。そうしないと、ポップオーバーが空に見えるからです。

class MyTableViewController: UITableViewController {
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        // this is Cartography syntax - the intention should be clear
        layout(view, replace: ConstraintGroup()) { [unowned self] view in
            view.width == self.tableView.contentSize.width
            view.height == self.tableView.contentSize.height
        }
        view.setNeedsLayout()
    }
} 

設定ポップオーバーはコンテンツで満たされていますが、そのサイズは適切ではありません:

ここに画像の説明を入力

これを修正するために、機能しない次のアプローチを試しました。

class MySettingsViewController: UIViewController {
    override var preferredContentSize: CGSize {
        get {
            let compressedSize = view.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
            // this is always (0, 0) because the subviews are not resized, yet 
            return compressedSize 
        }
        set {
            super.preferredContentSize = newValue
        }
    }
}

結論: 圧縮は機能しません。

4

1 に答える 1

0

そのため、Bitbucket リポジトリを見るとわかるように、自分で問題を修正しました。

と のレイアウトが修正されましMyTableViewControllerMySettingsViewController。前者は次のようになります。

class MyTableViewController: UITableViewController {

    var heightConstraint: NSLayoutConstraint?
    var tableViewEdgesConstraints: [NSLayoutConstraint]?

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        if let container = tableView.superview where tableViewEdgesConstraints == nil {
            layout(tableView, container, replace: ConstraintGroup()) { [unowned self] tableView, container in
                self.tableViewEdgesConstraints = tableView.edges == inset(container.edges, 0)
            }
        }
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        if let heightConstraint = heightConstraint {
            if Int(heightConstraint.constant) != Int(tableView.contentSize.height) {
                heightConstraint.constant = self.tableView.contentSize.height
            }
        } else {
            layout(view, replace: ConstraintGroup()) { [unowned self] view in
                if (self.tableView.contentSize.height > 0) {
                    self.heightConstraint = view.height == self.tableView.contentSize.height
                }
            }
        }
    }
} 

したがって、基本的には、テーブルの高さをコンテンツの高さに制約し、コンテンツの高さが変化した場合は制約を変更します。これは、テーブルがレイアウトされるとすぐに行われます。さらに、ネストされたテーブル ビューは、その端によってコンテナ ビューの端に固定されます。Interface Builder で異なるシーンの 2 つのビューを制限する方法が見つからなかったため、これは必須であると思います。

MySettingsViewControllerスクロールビューのサイズは、コンテンツ ビューのフレーム (アウトレット経由でアクセス可能) のサイズが判明するとすぐに、このサイズに設定されます。さらに、ポップオーバーを圧縮するために、高さが変化すると、設定コントローラーの preferredContentSize がそれに応じて調整されます (条件を省略すると、レイアウトの無限ループに陥る可能性があります。さらに、それを可能にするために 3 つのことを行いました。 MySettingsViewController にラップされたナビゲーション コントローラー:

  1. ポップオーバーの幅は固定値に設定されます (そうしないと、全幅に拡張されることがあります)。
  2. presentViewController の preferredContentSize は、等しく設定する必要があります。
  3. 醜い垂直オフセットを避けるために、scrollView のインセットを 0 に設定する必要がありました。しかし、それは機能します。

コードは次のとおりです。

class MySettingsViewController: UIViewController {

    @IBOutlet weak var contentView: UIView!
    @IBOutlet weak var scrollView: UIScrollView!

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        scrollView.contentSize = contentView.frame.size

        if (preferredContentSize.height != scrollView.contentSize.height) {
            let newSize = CGSize(width: 400, height: scrollView.contentSize.height)
            preferredContentSize = newSize
            presentingViewController?.presentedViewController?.preferredContentSize = newSize
            scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
        }
    }
}

そして、これは結果です:

ここに画像の説明を入力

于 2015-08-24T08:16:47.843 に答える