開発者の皆さん、私はInterface Builder(Xcode 5/iOS 7)のAutoLayoutで問題を抱えています。それは非常に基本的で重要なので、私は誰もがこれが正しく機能する方法を知っているべきだと思います。これがXcodeのバグであれば、それは重大な問題です。
だから、私がこのようなビュー階層を持っているときはいつでも私は問題にぶつかる:
>UIViewController
>> UIView
>>>UIScrollView
>>>>UILabel (or any other comparable UIKit Element)
UIScrollViewは、例えば、各辺から50px(問題なし)という強固な制約を有する。次にUILabelにTop Space制約を追加します(問題ありません)(ラベルの高さ/幅を固定することもできますが、何も変更されませんが、Labelの固有サイズのため不要になります)。
UILabelに末尾の制約を追加すると問題が発生します。
例:末尾のスペース:スーパービュー= 25
今2つの警告が発生します - そして私は理由がわかりません:
A) スクロール可能なコンテンツサイズのあいまいさ(スクロールビューのスクロール可能なコンテンツの高さ/幅があいまいです)
B) 見当違いのビュー(予想されるラベル:x = -67実際:x = 207)
私はあなたがダウンロードすることができる新しくて新しいプロジェクトでこの最小の例をしました、そして私はスクリーンショットを添付しました。ご覧のとおり、Interface Builderは、LabelがUIScrollViewの境界(オレンジ色の破線の四角形)の外側に配置されることを想定しています。問題解決ツールを使用してラベルのフレームを更新すると、そのフレームはすぐそこに移動します。
注意:UIScrollViewをUIViewに置き換えた場合、動作は予想通りです(ラベルのフレームは正しく、制約に従って)。そのため、UIScrollViewに問題があるか、重要なことを見逃しています。
IBが提案しているようにラベルのフレームを更新せずにアプリケーションを実行すると、それはまっすぐに配置され、UIScrollViewはスクロール可能になります。フレームを更新した場合、ラベルは見えなくなり、UIScrollViewはスクロールしません。
オビ=ワン・ケノービを助けて!なぜあいまいなレイアウトですか?なぜ見当違いのビュー?
ここからサンプルプロジェクトをダウンロードして、何が起こっているのかを理解できるか試してみてください。 https://github.com/Wirsing84/AutoLayoutProblem
注:iOS> 10.0では、これはテストされていません。したがって、特定の状況では解決方法が不完全になる可能性があります。
だから私はちょうどこのように整理しました:
UIScrollView
add a UIView
の中(我々はそれをcontentView
と呼ぶことができます);
このcontentView
では、上下左右の余白を0に設定(もちろんscrollView
であるsuperView
から); 縦方向と横方向の中央揃えも設定;
終了。
これで、すべてのビューをそのcontentView
に追加でき、contentSize
のscrollView
はcontentView
に従って自動的にサイズ変更されます。
更新:
このエラーが原因で追跡に時間がかかりました。最初はScrollViewのサイズを固定しようとしましたが、エラーメッセージには明らかに「コンテンツサイズ」と表示されます。 ScrollViewの上部から固定したものもすべて下部に固定されていることを確認しました。そのようにScrollViewはすべてのオブジェクトと制約の高さを見つけることによってそのコンテンツの高さを計算することができます。これはあいまいなコンテンツの高さを解決し、幅はかなり似ています...最初はScrollViewの中心にXを置いていましたが、オブジェクトをScrollViewの横に固定する必要もありました。 iPhone 6の方が画面が広くなる可能性があるため、これは嫌いですが、「あいまいなコンテンツの幅」エラーは解消されます。
それは私の自己回答式の質問に対する答えです UIScrollView + Centered View + Ambigous Scrollable Content Size +多くのiPhoneサイズ 。
しかし、それはあなたのケースも完全にカバーしています!
Has ambiguous scrollable content width
とHas ambiguous scrollable content height
。重要:あなたは末尾および/または下制約を追加する必要があります。 「一流でトップ」ではない - それはうまくいかない!
あなたは私の example project でそれをチェックすることができます。
P.S.
論理によると - このアクションは「矛盾する制約」を引き起こすはずです。しかし、違います。
なぜそれが機能するのか、そしてXcodeがどの制約がより優先順位が高いのかを検出するのかはわかりません(これらの制約を明確にするために優先順位を設定していないため)。誰かが説明してくれてありがたいです、なぜそれが以下のコメントでうまくいくのか。
下記のようにUIView
name__のサブビューとしてUIScrollView
name__を作成する必要があります。
UIViewController
name__UIView
'メインビュー' UIScrollView
name __ UIView
'コンテナビュー' 2番目のステップはUIScrollView
name__制約を作成することです。これをsuperViewの上下左右の制約で行いました。
次にUIScrollView
name__のコンテナーの制約を追加しましたが、ここから問題が始まります。同じ拘束(上、下、前、後)を設定すると、ストーリーボードに警告メッセージが表示されます。
「あいまいなスクロール可能なコンテンツの幅があります」および「あいまいなスクロール可能なコンテンツの高さがあります」
上記と同じ制約を続けて、メインビューとの関係でEqual Height
とEqual Width
をコンテナビューに追加するだけです。 しない あなたのUIScrollView
name__。つまり、コンテナビューの制約はUIScrollView
name__のスーパービューに関連付けられています。
その後、ストーリーボードに警告が表示されなくなり、サブビューに制約を追加し続けることができます。
iOS 12、Swift 4
autolayout
を使用する最も簡単な方法:
UIScrollView
を追加して0,0,0,0
をsuperview(またはご希望のサイズ)に固定しますUIView
を追加し、0,0,0,0
を4辺すべてに固定して、horizontally
とvertically
を中央に配置します。bottom
とalign center Y
の優先度を250に変更します。(水平スクロールの場合はtrailing
とalign center X
を変更します)遅れるかもしれませんが、次の解決策 追加コードなしでこの種の問題を解決します ストーリーボードを使用するだけです。
あなたのコンテンツビューのために、あなたはscrollviewと これはコンテンツビューフレームを変更しないでしょう のために先行/末尾/上/下のスペースに対する制約を設定する必要があります:
もちろん、スクロールビューでコンテンツのサイズがわかるように、コンテンツビューに対して追加の制約を作成する必要があります。たとえば、固定の高さと中心のxを設定します。
お役に立てれば。
スクロールビューを機能させ、自動レイアウトで完全にスクロールできるようにする方法については、このチュートリアルとポイントチュートリアルをご覧ください。今、まだ私を困惑させているのは、スクロールビューのコンテンツサイズが常に必要なサイズよりも大きいためです。
http://samwize.com/2014/03/14/how-to-use-uiscrollview-with-autolayout/ /
@Matteo Gobbiの答えは完璧ですが、私の場合はスクロールビューがスクロールできません。 " align center Y "を削除して " height> = 1 "を追加すると、スクロールビューはスクロール可能になります
スクロールしないでuiscrollviewに苦しんでいる人はあなたの最後のビューの下のレイアウト(これはあなたのコンテンツビューの内側にある)であなたのコンテンツビューの下の制約を設定するだけです。中心Y拘束を削除することを忘れないでください。
他のすべての制約は上で定義したものと同じです。 Scrollviewは、そのコンテンツビューから最大の高さを取得することだけを考慮しており、最後のビューの下部の制約として設定しています。つまり、Scrollviewは自動的にコンテンツオフセットを変更します。
私の場合、最後のビューはno of linesプロパティ= 0(コンテンツに応じて自動的に高さを調整)でUILableでしたので、uilableの高さは動的に増加し、最終的にuilableの下部レイアウトがコンテンツビューの下部と揃うためスクロール可能領域が増えます。これにより、scrollviewはコンテンツのオフセットを増やすように強制されます。
import UIKit
class ViewController: UIViewController {
//
let scrollView: UIScrollView = {
let sv = UIScrollView()
sv.translatesAutoresizingMaskIntoConstraints = false
return sv
}()
let lipsumLbl: UILabel = { // you can use here any of your subview
let lbl = UILabel()
lbl.translatesAutoresizingMaskIntoConstraints = false
lbl.text = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce eleifend nisi sit amet mi aliquet, ut efficitur risus pellentesque. Phasellus nulla justo, scelerisque ut libero id, aliquet ullamcorper lectus. Integer id iaculis nibh. Duis feugiat mi vitae magna tincidunt, vitae consequat dui tempor. Donec blandit urna nec urna volutpat, sit amet sagittis massa fringilla. Pellentesque luctus erat nec dui luctus, sed maximus urna fermentum. Nullam purus nibh, cursus vel ex nec, pulvinar lobortis leo. Proin ac libero rhoncus, bibendum lorem sed, congue sapien. Donec commodo, est non mollis malesuada, nisi massa tempus ipsum, a varius quam lorem vitae nunc.
Cras scelerisque nisi dolor, in gravida ex ornare a. Interdum et malesuada fames ac ante ipsum primis in faucibus. Maecenas vitae nisl id erat sollicitudin accumsan sit amet viverra sapien. Etiam scelerisque vulputate ante. Donec magna nibh, pharetra sed pretium ac, feugiat sit amet mi. Vestibulum in ipsum vitae dui vehicula pulvinar eget ut lectus. Fusce sagittis a elit ac elementum. Fusce iaculis nunc odio, at fermentum dolor varius et. Suspendisse consectetur congue massa non gravida. Sed id elit vitae nulla aliquam euismod. Pellentesque accumsan risus dolor, eu cursus nibh semper id.
Vestibulum vel tortor tellus. Suspendisse potenti. Pellentesque id sapien eu augue placerat dictum. Fusce tempus ligula at diam lacinia congue in ut metus. Maecenas volutpat tellus in tellus maximus imperdiet. Integer dignissim condimentum lorem, id luctus nisi maximus at. Nulla pretium, est sit amet mollis eleifend, tellus nulla viverra dolor, ac feugiat massa risus a lectus. Pellentesque ut pulvinar urna, blandit gravida ipsum. Nullam volutpat arcu nec fringilla auctor. Integer egestas enim commodo, faucibus neque ac, rutrum magna. Vivamus tincidunt rutrum auctor. Cras at rutrum felis. Fusce elementum lorem ut pharetra venenatis.
"""
lbl.textColor = .darkGray
lbl.font = UIFont.systemFont(ofSize: 16)
lbl.numberOfLines = 0
return lbl
}()
//======================================================================//
//
// MARK:- viewDidLoad
//
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
setupAutoLayout()
}
func setupViews() {
title = "ScrollView Demo"
view.backgroundColor = .white
view.addSubview(scrollView)
scrollView.addSubview(lipsumLbl)
}
func setupAutoLayout() {
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
lipsumLbl.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
lipsumLbl.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
lipsumLbl.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
lipsumLbl.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
lipsumLbl.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
}
}
出力:
ContentView(UView
)をUIScrollView
内のコンテナーとして使用し、スーパービュー(top
)およびbottom
のエッジ(trailing
、leading
、UIScrollView
、contentView
)に固定すると、equalwidth
およびequalheight
がスーパービューになります。これらは制約です。そして、メソッドの呼び出し:
-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
self.scrollView.contentSize = self.contentView.frame.size;
}
私のために問題を解決しました。
YouTubeでビデオを作りました
Xcodeのストーリーボードのみを使用してStackViewをスクロールします
ここには2種類のシナリオが現れると思います。
ScrollView内のビュー -
UIView
)UIStackView
)どちらの場合も垂直方向にスクロール可能なビューの場合は、次の制約を追加する必要があります。
上、左、下、右から4つの拘束。
スクロールビューと同じ幅(水平方向のスクロールを停止するため)
あなたは彼自身の本質的な内容の高さを持っているビューに対して他のいかなる制約も必要としません。
本質的なコンテンツの高さがないビューの場合は、高さの制約を追加する必要があります。高さの制約がscrollViewの高さよりも大きい場合にのみ、ビューはスクロールします。
Interface BuilderのサイズインスペクタでViewController(UIScrollViewを保持しているもの)のサイズをFreeformに設定すればすべてうまくいくはずです。
含まれるUIViewcontrollerのためのInterface BuilderのSizeインスペクタでのFreeform設定
垂直スクロール
スクロールビューの上から下に向かって連続した制約の行を作成する方法があることを確認するだけです。 [-X-X-X]
私の場合 - 水平スクロールスクロールビュー - Appleのテクニカルノート はあなたにこれを教えていませんが、私はスクロールビューのそれぞれの子に幅と高さの制約を追加する必要もありました。
[XCode 7.2およびiOS 9.2用にテスト済み]
ストーリーボードのエラーと警告を抑制したのは、スクロールビューとコンテンツビュー(私の場合はスタックビュー)の 固有のサイズ を Placeholder に設定することでした。この設定は、ストーリーボードのサイズインスペクタにあります。そしてそれは言います - Interface Builderで編集している間、デザイン時の本質的なコンテンツサイズを設定することはビューに影響するだけです。実行時には、ビューはこの固有のコンテンツサイズを持ちません。
だから、これを設定しても問題ないと思います。
注:ストーリーボードでは、scrollviewのすべての端をスーパービューに、stackviewのすべての端をscrollviewに固定しました。私のコードでは、スクロールビューとスタックビューの両方で translateAutoresizingMaskIntoConstraints をfalseに設定しました。そして私は内容のサイズについて言及していません。スタックビューが動的に大きくなると、ストーリーボードで設定されている制約によってスタックが確実にスクロール可能になります。
ストーリーボードの警告は私を怒らせていたので、警告を抑えるためだけに物事を水平方向または垂直方向に集中させたくはありませんでした。
Swift 4+アプローチ:
1)UIScrollViewの上下左右の余白を0に設定します。
2)UIScrollView内にUIViewを追加し、上下左右の余白を0に設定します(UIScrollViewの余白と同じ)。
3)最も重要な部分は幅と高さを設定することです ここで高さの制限は低い優先順位を持つべきです 。
private func setupConstraints() {
// Constraints for scrollView
scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
// Constraints for containerView
containerView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
containerView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
containerView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
containerView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
let heightConstraint = containerView.heightAnchor.constraint(equalTo: scrollView.heightAnchor)
heightConstraint.priority = UILayoutPriority(rawValue: 250)
heightConstraint.isActive = true
}
私は同じエラーを受けていました..私は以下をやっています
ScrollView(2)の先頭/末尾/上/下を追加し、次にUIView(3)を追加します。
表示(1)と表示(3)を選択して、身長と体重を等しく設定します。
私は役立ちますビデオをやっています:
ここに示すように、私がしたのは別のコンテンツビューを作成することです。
コンテンツビューはフリーフォームであり、すべてのサブビューを追加することができます。コンテンツビューには独自の制約があります。
UIScrollViewがメインのView Controllerに追加されます。
プログラム的にIBOutletを介してリンクされているcontentViewをクラスに追加し、UIScrollViewのcontentViewを設定します。
右側のスクロールバーのスクロールバーに気づいてもコンテンツが移動しないという動作を誰かが受けている場合、この事実はおそらく考慮する価値があります。
スクロールビューのコンテンツとスクロールビューの外側のオブジェクトとの間の制約を使用して、スクロールビューのコンテンツの固定位置を指定し、そのコンテンツがスクロールビューの上に浮かぶように表示することもできます。
それはAppleの ドキュメンテーション からのものです。たとえば、誤って一番上のLabel/Button/Img/Viewをスクロール領域の外側のビュー(おそらくヘッダーまたはscrollViewの真上にあるもの)に固定した場合は、contentView全体を所定の位置に固定します。