基本的に、アラートのタイトルとメッセージセクションの動作を再現しようとしています。
タイトルとメッセージのラベルがスクロールビューに表示されます。ラベルテキストが増加すると、アラートの高さもラベルの固有のコンテンツサイズとともに増加します。ただし、特定の高さになると、アラートの高さが増加しなくなり、タイトルとメッセージテキストがスクロール可能になります。
私が読んだもの:
記事
スタックオーバーフロー
答えはそこにあるかもしれませんが、私はそれを抽象化することができませんでした。
私が試したこと:
2つのラベルが付いたスクロールビューにのみ焦点を当てて、親ビューがスクロールビューの本来の高さに応じてサイズ変更される最小限の例を作成しようとしました。私はたくさんの制約で遊んできました。これが機能しない(多くの中で)1つのコンボです:
自動レイアウト と 通常の制約 、さらには 固有のコンテンツサイズ で作業しました。また、私は知っています 自動レイアウトで動作する基本的なスクロールビューを取得する方法 。しかし、私は優先順位とコンテンツのハグと圧縮抵抗で何もしていません。私が行った読書から、私はそれらの意味を表面的に理解していますが、この場合にそれらをどのように適用するか途方に暮れています。私の推測では、コンテンツのハグと優先順位を使って何かをする必要があります。
純粋な自動レイアウトであなたが望んでいたのと同様の効果を達成したと思います。
構造
まず、私の構造をお見せしましょう。
コンテンツビューは背景が白のビューで、発信者ビューと底面ビューの高さは固定されています。底面図にはボタンがあり、発信者ビューにはタイトルがあります。
ソリューション
したがって、基本的な制約を設定した後(スクロールビュー内のビューには、スクロールビューに対して上、左、右、下があり、同じ幅があることに注意してください)、問題は、スクロールビューがどのサイズにするべきかわからないことです。だからここに私がしたことが来ます:
スクロールが最大になるまで成長できるようにしたかったのです。そこで、その最大値を設定するスーパービューに比例した高さを追加しました。
ただし、これには2つの問題があります。スクロールビューはまだ高さを認識していないため、サイズを変更でき、スクロールビューはコンテンツのサイズを渡します(コンテンツが最大サイズよりも小さい場合)。
したがって、両方の問題を解決するために、スクロールビュー内のビューとスクロールビューから同じ高さをより小さな優先度で追加しました
これがお役に立てば幸いです。
あなたの問題は制約だけでは解決できません、あなたはいくつかのコードを使わなければなりません。これは、スクロールビューに固有のコンテンツサイズがないためです。
したがって、スクロールビューのサブクラスを作成します。たぶん、プロパティやデリゲートなどを与えて、最大の高さを教えてください。
サブクラスでは、コンテンツサイズが変更されるたびに組み込みコンテンツサイズを無効にし、新しい組み込みサイズをコンテンツサイズの最小値と最大許容サイズとして計算します。
スクロールビューに固有のサイズが設定されると、スクロールビューとそのスーパービューの間の制約により、実際には問題に対して意味のあることが行われます。
純粋な自動レイアウトを介してこのソリューションを実現できるはずです。
通常、コンテンツが垂直方向に大きくなるにつれてラベルを大きくしたい場合は、これを行います
[label setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
[label setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
スクロールビューを要件に準拠させるには、スクロールビューの上部をラベルからスクロールビューの下部まで結ぶ線を描画して、高さを計算できるようにする必要があります。スクロールビューをその親に限定するために、たとえば0.8のスーパービューの乗数を使用して高さの制約を設定できます。
これは、2つの制約でかなり簡単に行うことができます
AutoLayoutは、scrollViewをcontentSizeに維持しようとしますが、最大の高さに一致すると「あきらめ」、そこで停止します。
唯一注意が必要なのは、制約2の高さを設定することです。
UIStackViewがUIViewControllerにある場合、それはviewWillLayoutSubviews
で行います。
これを実現するためにUIScrollViewをサブクラス化する場合は、updateConstraints
で実行できます。
何かのようなもの
override func viewWillLayoutSubviews() {
scrollViewHeightConstraint?.constant = scrollView.contentSize.height
super.viewWillLayoutSubviews()
}
AutoLayout制約のみで、この正確な動作を実現することができました。これを行う方法の一般的なデモを次に示します。適切と思われるビュー階層に適用できます。
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let kTestContentHeight: CGFloat = 1200
// Subview that will shrink to fit content and expand up to 50% of the view controller's height
let modalView = UIView()
modalView.backgroundColor = UIColor.gray
// Scroll view that will facilitate scrolling if the content > 50% of view controller's height
let scrollView = UIScrollView()
scrollView.backgroundColor = .yellow
// Content which has an intrinsic height
let contentView = UIView()
contentView.backgroundColor = .green
// add modal view
view.addSubview(modalView)
modalView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([modalView.leftAnchor.constraint(equalTo: view.leftAnchor),
modalView.rightAnchor.constraint(equalTo: view.rightAnchor),
modalView.heightAnchor.constraint(lessThanOrEqualTo: view.heightAnchor,
multiplier: 0.5),
modalView.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
let expandHeight = modalView.heightAnchor.constraint(equalTo: view.heightAnchor)
expandHeight.priority = UILayoutPriority.defaultLow
expandHeight.isActive = true
// add scrollview to modal view
modalView.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([scrollView.topAnchor.constraint(equalTo: modalView.topAnchor),
scrollView.leftAnchor.constraint(equalTo: modalView.leftAnchor),
scrollView.rightAnchor.constraint(equalTo: modalView.rightAnchor),
scrollView.bottomAnchor.constraint(equalTo: modalView.bottomAnchor)])
// add content to scrollview
scrollView.addSubview(contentView)
contentView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([contentView.leftAnchor.constraint(equalTo: scrollView.leftAnchor),
contentView.widthAnchor.constraint(equalTo: modalView.widthAnchor),
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
contentView.heightAnchor.constraint(equalToConstant: kTestContentHeight)])
let contentBottom = contentView.bottomAnchor.constraint(equalTo: modalView.bottomAnchor)
contentBottom.priority = .defaultLow
contentBottom.isActive = true
}
}
私のプロジェクトにも同様の問題があります。次の方法を使用して、回避することができます。
まず、タイトルとボトムアクションの高さが固定されています。コンテンツの高さは可変です。 font-sizeを使用してmainViewを1つの子として追加し、layoutIfNeededを呼び出すと、その高さを計算してXXとして保存できます。次に、mainViewから削除しました。
次に、通常の制約を使用してスクロールビューでコンテンツパーツをレイアウトすると、mainViewの高さ制約はXXで、setContentCompressionResistancePriority(.defaultLow、for:.vertical)になります。
最後に、アラートは、コンテンツが短い場合は正確なサイズを表示し、スクロールすると長いサイズの場合は制限されたサイズを表示できます。