混合および純粋な自動レイアウトアプローチ のさまざまなソリューションを試して2日間を費やして、自動レイアウト前のささいなスクロールビューのセットアップを達成しました。私はこれをほとんどストーリーボードで設定しています(まあ、それはただの方法です)。
だからここに助けを求めます。
ビューツリー:
UIView
-UIView
-UIView
..-UIScrollview
...-UIButton
...-UIButton
...-UIButton
ボタンは水平にスクロールすることになっています(左から右へ、またはその逆)。誰かplease純粋なAutolayoutを使用してこれを達成するための制約の設定方法を教えてください。
-
私は次のような混合アプローチを試みました:
UIView
- UIView
- UIView
..-UIScrollview
...-UIView (contentview)
....-UIButton
....-UIButton
....-UIButton
...およびAppleのTechNoteに従って、contentview
およびtranslatesAutoresizingMaskIntoConstraints
設定の固定幅と高さの制約を設定します。ボタンとスクロールビューは、制約を使用して設定されます。これはスクロールビューのスクロールを取得します(はい)が、残念ながらスクロールしすぎです!私が知る限り、スクロールの幅は、コンテンツビューを設定した値の2倍になります。
contentview
を使用する場合と使用しない場合の両方で、純粋な自動レイアウトアプローチも試しました。 AllビューはtranslatesAutoresizingMaskIntoConstraints=NO
です(self.view
を除く)。ボタンには固定幅/高さの制約があり、スクロールビューの4つのすべての端に固定されています。何もスクロールしません。
だから、なぜ私はそれを正しく動作させることができないのか完全に困惑しています。どんな助けでも大歓迎です、そして、あなたが他の情報が必要であるならば、尋ねてください!
更新されたスクリーンショット-buttonZ制約:
EDIT @ Jamie Forrestそのため、ソリューションは最後のボタンの間違ったトレーリング制約であることが判明しました。 6441の代わりに、設定した値は負の-6441でした。トリッキーなことは、ストーリーボードで値を設定するときに、ピンツールバーに2つのオプションがあることです。
現在のキャンバス値は負(スクロールなし)であり、以下のオプションは正(スクロールをアクティブ化)です。これは私が愚かではないことを意味しますが、少なくとも半盲目だと思います。 私の防御のために、XCodeが「誤った」設定に対してエラーを表示しないことは多少不安になりませんか?
EDITED AGAINこれはおかしいです...末尾の値を-6441(スクロールなし)から6441対応スクロールに変更します。しかし、私の旧友である「コンテンツサイズが大きすぎます」が復活し、コンテンツサイズが本来の2倍になりました。正しいコンテンツスクロールを取得するための解決策は、末尾の制約をゼロに設定することでした! Storyboardで作業しているとき、これは明らかではありませんが、@ Infinity Jamesのコードを見れば、それは本来あるべきことです。
ここに貼り付けたように、制約の正確な値と設定を確認するのは難しいので、間違ったスクリーンショットを見てもわからない。
セットアップの何が問題なのかを説明する代わりに、基本的な サンプルプロジェクト を作成しました。ビュー階層と制約のセットアップは、説明したものと非常によく似ています。水平スクロールは、Appleが テクニカルノート で説明している「Pure AutoLayout」アプローチを使用するサンプルプロジェクトで期待どおりに機能します。
また、元々、自動レイアウトをUIScrollView
name__で動作させるのに苦労しました。スクロールビューのすべてのアイテムをまとめて、最終的にスクロールビューのすべての側面にリンクし、AutoLayoutシステムがcontentSizeを決定できるようにする制約があることを確認することが重要です。フレームより大きいスクロールビュー。あなたのコードでそれをやろうとしているように見えますが、多分あなたはそこにcontentSizeを小さくしすぎている余分な制約がありました。
また、AutoLayoutとUIScrollviewで他の人が述べたように、contentSizeを明示的に設定しなくなったことにも注意してください。 AutoLayout Systemは、制約に基づいてcontentSizeを計算します。
また、 この電子ブックの章 は、このすべてがどのように機能するかを理解するのに非常に役立つことがわかりました。これがすべて役立つことを願っています。
愚かなクラブへようこそ。私は創立者の一人です。 :D
垂直スクロールの場合:動作させる唯一の方法(iOS 8、Xcode 6、および純粋な自動レイアウト)は、スクロールビューに次の制約を追加することでした(すべてスーパービューに関連):
私の構造:
UIView
- ScrollView
- Subview
- Subview
- Subview
- Subview
- ...
これが最終結果です。
これがセットアップです:
うまくいけば、これで誰かが眠りにつく_AT 5 AMから救われることを願っています。 :D
質問に対する投票数が多いことと回答に対する投票数が少ないことから判断すると、人々はここで理解できる迅速な解決策を見つけていません。追加してみましょう。このプロジェクトは、Interface Builderで完全に実行される自己完結型の例です。 10分以内に作業ができるはずです。その後、学習した概念を自分のプロジェクトに適用できます。
元の質問は、スクロールボタンについて尋ねています。ここではUIView
sを使用していますが、好きなビューを表すことができます。ストーリーボードのスクリーンショットはこの形式の方がコンパクトなので、水平スクロールも選択しました。ただし、垂直スクロールの原理は同じです。
UIScrollView
は1つのサブビューのみを使用する必要があります。これは、スクロールするすべてのものを保持するコンテンツビューとして機能する「UIView」です。単一のビューアプリケーションにできます。
この例では、水平スクロールビューを作成します。 View Controllerを選択してから、Size InspectorでFreeformを選択します。幅を1,000
、高さを300
にします。これにより、ストーリーボード上にスクロールするコンテンツを追加する余地ができます。
スクロールビューの追加
UIScrollView
を追加して、4つの側面すべてをView Controllerのルートビューに固定します。
コンテンツビューの追加
UIView
をサブビューとしてスクロールビューに追加します。 これが重要です。スクロールビューに多くのサブビューを追加しようとしないでください。単一のUIView
を追加するだけです。これは、スクロールする他のビューのコンテンツビューになります。コンテンツビューをスクロールビューに4つの側面すべてに固定します。
等しい高さ
ドキュメントの概要で、 Command コンテンツビューとスクロールビュー親ビューの両方をクリックして、両方を選択します。次に、高さが等しくなるように設定します(Control コンテンツビューからスクロールビューにドラッグします)。 これも重要です。水平方向にスクロールしているため、スクロールビューのコンテンツビューは、この方法で設定しない限り、どのくらいの高さになるかわかりません。
注意:
コンテンツの追加
3つのUIView
sを追加し、それらにすべての制約を与えます。すべてに8ポイントのマージンを使用しました。
制約:
幅の制約を設定することも重要です。スクロールビューは、コンテンツビューの幅を知ることができます。
それで全部です。これでプロジェクトを実行できます。この回答の上部にあるスクロール画像のように動作するはずです。
垂直スクロールの場合、この例のすべての幅と高さの方向を入れ替えるだけです(テスト済みで動作中)。
ContentScrollは、UIScrollView内の制約を適用することで暗黙的に設定されます。
たとえば、UIView内にUIScrollViewがある場合、これは次のようになります(ご存じのとおりです)。
UIView *containerView = [[UIView alloc] init];
UIScrollView *scrollView = [[UIScrollView alloc] init];
[containerView addSubview:scrollView];
containerView.translatesAutoresizingMaskIntoConstraints = NO;
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(containerView, scrollView);
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|"
options:kNilOptions
metrics:nil
views:viewsDictionary]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|"
options:kNilOptions
metrics:nil
それにより、scrollViewがcontainerViewのサイズに合わせて設定されます(したがってcontainerViewは特定のサイズである必要があります)。
次に、次のようなボタンを保持するのに十分な大きさに暗黙的に設定することにより、UIScrollViewのcontentSizeを調整できます。
UIButton *buttonA = [[UIButton alloc] init];
UIButton *buttonB = [[UIButton alloc] init];
UIButton *buttonC = [[UIButton alloc] init];
[scrollView addSubview:buttonA];
[scrollView addSubview:buttonB];
[scrollView addSubview:buttonC];
buttonA.translatesAutoresizingMaskIntoConstraints = NO;
buttonB.translatesAutoresizingMaskIntoConstraints = NO;
buttonC.translatesAutoresizingMaskIntoConstraints = NO;
viewsDictionary = NSDictionaryOfVariableBindings(scrollView, buttonA, buttonB, buttonC);
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[buttonA]-|"
options:kNilOptions
metrics:nil
views:viewsDictionary]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[buttonA]-[buttonB]-[buttonC]-|"
options:NSLayoutFormatAlignAllBaseline
metrics:nil
views:viewsDictionary]];
UIScrollViewでAutoLayoutを使用することについて非常に多くの質問がありますが、無視する重要なポイントは、UIScrollViewの内部ビューがContent Viewに対して制約を作成することですが、 UIScrollView自体ではありません。 テクニカルノートTN2154 を参照してください。
UIScrollViewクラスは、境界のOriginを変更してコンテンツをスクロールします。これを自動レイアウトで機能させるために、スクロールビュー内の上端、左端、下端、および右端は、コンテンツビューの端を意味するようになりました。
次の図にそれを示します。
末尾のスペースは500ポイントであることがわかります。制約がUIScrollViewに対して行われた場合、ビューは配置されず、フレームを更新する必要があります。ただし、警告もエラーもありません。すべての制約がコンテンツビューに対するものだからです。
UIScrollViewは、内部ビューの制約に従ってコンテンツビューのサイズを計算します。 (例では、コンテンツサイズ:幅= 100(先頭のスペース)+ 200(ビューの幅)+ 500(末尾のスペース)、高さ= 131(上部の間隔)+ 200(高さ)+ 269(下部の間隔)
UIScrollViewでビューに制約を追加する方法:
そして、すべて完了です。
ScrollviewでAutoLayoutを処理する簡単な方法は、スクロールビュー内のすべてのサブビューを含むコンテナビューを追加することです。
結論:UIScrollViewを使用したAutoLayoutを理解するための重要なポイントは、内部ビューであり、UIScrollView自体ではなくコンテンツビューに対して制約を作成することです。
添付 サンプルコード
次のソリューションは、autolayoutを使用しcontentSizeを使用しないscrollViewで機能しました。
これで完了です。これで、このビューに任意の数のコントロールを追加し、相互に関連する制約を適用できます(このビューがないと機能しないようです)。このビューを使用しない場合は、scrollViewに関連する(相互に関連しない)各コントロールに制約を適用する必要があります。
クリティカル。わかりやすくするために、UIScrollViewが1000幅および100の高さであるとします。 (実際、通常、これらの値は、デバイスの幅などに応じて、もちろん動的になります。しかし、今のところは、幅1000と高100とだけ言ってください。)水平スクロールをしているとしましょう。そのため、UIScrollView内にUIViewを配置します。 (これが「コンテンツビュー」です。)コンテンツビューの4つのすべての制約をスクロールビューに設定します。 それが間違っているように見える場合でも、それらをすべてゼロにします。コンテンツUIViewの高さを100に設定し、それを忘れます。さて、水平にスクロールしたいので、コンテンツビューの幅を1225に設定します。
コンテンツビューの幅は、親スクロールビューの幅よりも225大きいことに注意してください。大丈夫です。実際、あなたはそれをしなければなりません。ご了承ください
幅を「一致」させる必要があると思います通常どおり。しかし、それを行うと、まったく機能しません。
興味深いことに、実際には先頭/末尾の数値を任意の正値(「50」と言ってください)に設定できます。これにより、バウンスのマージンが得られます。 (よく見かけます:試してみてください。)どちらかの端に負の値があると、「静かに壊れます」。
腹立たしいことに、Xcode(とにかく7.3.1のように)、
自動的にそれらを集計しようとするためです。もしそうなら、それは静かに壊れます。最初のインスタンスで4つの値をすべてゼロに設定します。また、コンテンツビューの幅を例の「1000」よりもはるかに広く設定します。
編集:私はほとんどの要件にUIScrollViewの代わりにUITableViewを使用することになりました。 tableViewのほうがはるかに柔軟で動的なようです。
私はあなたがthecontentSize
の問題に直面していると思います。 「純粋な」AutoLayoutアプローチを使用する場合のcontentSize
の処理方法について このブログ投稿 を確認してください。その要点は、制約がコンテンツサイズを暗黙的に定義することです。 AutoLayoutを使用する場合、決して明示的に設定しないでください。ブログ投稿の最後にサンプルプロジェクトを添付して、その仕組みを示しています。
このようにレイアウトを整理する必要がありますViewControllerView
にはScrollView
が含まれ、ScrollView
にはContainerView
が含まれ、ContainerView
には2つのLabels
が含まれます
次に、ScrollView
がスクロールできるようにするために、3つの手順を実行します
ScrollView
ピン(上/右/下/左)をViewControllerView
に設定ContainerView
ピン(上/右/下/左)をScrollView
に設定Horizontally in Container
を設定(do n'tVertically in Container
を設定)Label1
ピン(top/ right/left)to ContainerView
Label1
pin(right/left /bottom)to ContainerView
andtopto Label1
この助けを願っています
テクニカルノートには、あなたが見たかもしれない部分があります。スクロールビューの端に固定された制約を使用して、スクロールビューのコンテンツサイズを暗黙的に設定できます。
以下に簡単な例を示します。スクロールビューが1つのビューを1つ持つストーリーボードを作成します。スクロールビューの制約を設定して、配置するビューのサイズに合わせます。
そのスクロールビュー内に単一のビューを追加します。制約を使用してそのビューのサイズを明示的に設定します(サイズがスクロールビューよりも大きいことを確認します)。
次に、内部ビューの4つのエッジをその親スクロールビューにロックする4つの制約をその内部ビューに追加します。これらの4つの制約により、コンテンツサイズが拡大して内部ビューに対応します。
複数のビューをスクロールビューに追加する場合、たとえば水平にレイアウトする場合、最初のサブビューの左側をスクロールビューの左側にロックし、サブビューを互いに水平にロックし、右側をロックしますスクロールビューの右側の最後のサブビューの側面。これらの制約は、スクロールビューのコンテンツサイズを拡張して、すべてのサブビューとその制約に対応させます。
あなたの質問が「フォーカスがあるときにキーボードの邪魔にならないように、垂直スクロールUIScrollViewに多数のUITextFieldsを配置する方法」の場合、最良の答えは次のとおりです。
しないでください。
代わりに、静的セルを含むUITableViewControllerを使用します。
このスクロールアウトの動作は無料で得られます。また、View ControllerがUINavigationController内に表示されている場合、すべてのコンテンツインセットは動作します。
IOS 8.4、Xcode 6.4で今日抱えている同様の問題
サブビューを含むcontentView(UIView)を含むスクロールビューを含むビューがあります。
すべてが自動レイアウトです。スクロールビューのエッジは、制約付きで親ビューのエッジに固定されます。コンテンツビューの端は、制約付きでスクロールビューの端に固定されます。
もともと、コンテンツビューはスクロールビューの全幅としてのサイズ変更を拒否していました。コンテンツビューに追加の制約を追加して、その幅を親スクロールビューと一致させる必要がありました。または、contentView.centerX == scrollView.centerX制約を設定できます。それらのいずれかがエッジを固定することに加えて、コンテンツビューを突然適切なサイズにしました。
// Either one of these additional constraints are required to get autolayout to correctly layout the contentView. Otherwise contentView size is its minimum required size
scrollView.addConstraint(NSLayoutConstraint(item: contentView, attribute: .CenterX, relatedBy: .Equal, toItem: scrollView, attribute: .CenterX, multiplier: 1.0, constant: 0))
scrollView.addConstraint(NSLayoutConstraint(item: contentView, attribute: NSLayoutAttribute.Width, relatedBy: .Equal, toItem: scrollView, attribute: .Width, multiplier: 1.0, constant: 0.0))
フォームの視覚的制約を使用して、コンテンツビューの端をスクロールビューに固定します。
let cvConstraints = ["H:|[contentView]|", "V:|[contentView]|"]
ルーチンを使用して配列を反復処理し、scrollViewに追加します。
同様の問題に直面しました。私はすべてに制約を設定し、なぜそれがまだいくつかのサブビューのサイズを変更するのか疑問に思っていました。私の解決策はclipsToBoundsをYESに設定することでした。
純粋な自動レイアウトのアプローチは見事に機能しますが、非自動レイアウトから移行する場合、セットアップするのは非常に苦痛です。私はそれを数回やったことがあり、いくつかの一般的なヒントがあります:
私のように、サブビュー内で制約のない静的コンテンツを使用する場合は、次のようにできます。
override func viewDidLayoutSubviews() {
scrollView.contentSize = CGSizeMake(320, 800)
}
AutoLayoutビューの埋め込みScrollviewを使用して、表示画面のスクロールビューを中央に配置する方法の解決策を見つけるために何日も費やしました。
私はAutolayoutのみでそれをしようとして数日を費やし、近づきましたが、決して十分に近づきませんでした。したがって、最終的には、viewDidLoadで、画面ごとに3行のコードも追加する必要がありました。
以下の解決策を参照してください。
ここで、.mファイルに移動して、これらのコード行をviewDidLoadに追加します(正しい頂点のセンタリングを得るためにパディング量で再生します)
if (IPAD)
{self.constraintVertVtoSV.constant = 150.0; }
これはすべてのデバイスで実行され、適切に中央揃えされ、適切にスクロールされるはずです。
この問題に対処した後、ようやく解決策を見つけました。私はユニバーサルクラスサイズのストーリーボード(600x600)を使用しています。 scrollViewのサイズのUIView(contentView)を作成し、scrollViewのTop、Bottom、Leading、Trailingに制約を作成しました。次に、contentViewのサイズを手動で600x600にクリップしました。ストーリーボードはすべてのサイズを変更しようとするのをやめ、私は仕事をすることができましたが、実際のデバイスまたはシミュレーターではビューがひどく見えました。このクリップサイズの制約アウトレットを2つ作成しました。
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewWidthConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewHeightConstraint;
次に、viewDidLoadで
CGSize viewSize = self.view.frame.size;
self.contentViewWidthConstraint.constant = viewSize.width;
self.contentViewHeightConstraint.constant = viewSize.height;
よく働く。
Swiftでは、この作業ソリューションを使用できます。
制約
ScrollView
:先頭、末尾、上部、下部=スーパービュー
ContentView
:先頭、末尾、上部、下部= ScrollView。コンテンツに固定/相対的な高さ。
幅の制約(contentView)をscrollviewsスーパービューに等しく設定できますが、プログラムで制約を追加するため、ビルド時にremove removeを選択します。これは、IBが警告で文句を言わないようにするためです。
extension UIView {
func setupContentViewForViewWithScroll(contentView vwContent : UIView) {
//Set constraint for scrollview content
let constraint = NSLayoutConstraint(item: vwContent, attribute: NSLayoutAttribute.Width, relatedBy: .Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: self.bounds.size.width)
vwContent.addConstraint(constraint)
self.layoutSubviews()
}
}
そして、View Controller viewDidLayoutSubviews
でこのメソッドを呼び出すだけです:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.view.setupContentViewForViewWithScroll(contentView: vwContent)
}
これは素人向けのソリューションであり、Appleがドキュメントで提案しているものではないことはわかっていますが、異なるコンテンツで非常に迅速にセットアップできる2回機能しました:ストーリーボードビューコントローラーにUIViewを挿入します。 UIViewに、Table View、Dynamic、0 Prototype cells、Style PlainまたはGroupedを挿入します。テーブルビューでスクロールビューを挿入し、スクロールビューでコンテンツを挿入します。それだけです。カスタムView Controllerの設定はありません。