UIScrollViewとAutoLayout

UIScrollViewとAutoLayoutに関する話題です。
このコンビネーションですが, 今のところ完全な解決に至っていません。とりあえず所望の動作は得られましたがといったところです。
iOS6からAutoLayoutが導入されました

さてつくりたいUIというのが, UIScrollViewを配置して, その中にUIViewControllerで操作を書いたViewをいれるというものです
通常であれば, UIScrollViewをInterfaceBuilderで配置して, weakリファレンスをして, その中に, UIViewControllerのインスタンスのパラメータviewを取り出して, addSubViewとここまではO.K.

UIScrollViewで起こる問題

  • ContentSizeを設定しても反映されない
  • UIScrollViewのSubViewにframeを指定しても, 全部左端にいく

筆者がはまったのは, 2つめのやつです. AppleのDocumentには確かにそれらしきことが書いていましたが…
いずれも– (void) viewDidLayoutSubviewsもしくはそのあたりで,
自動的にパラメータを調整する(よけいなお世話だ)のが原因.
てっとり早い解決策としては, AutoLayoutをOffするという手もありますが, ほかのViewもあるので, そうはいかないでしょう.

実装する方法によってかなり違うよう

UIをつくるにはいくつかあるので, それによってデフォルトパラメータなどの問題もあるので結構やっかいです

  • storyboardでUIViewControllerを作成
  • xibでUIView
  • コードでUIScrollViewをつくる

上二つは, InterfaceBuilderでパラメータを指定する

ここで気になるパラメータを…
InterfaceBuilderの Autoresize Subviews, Resize View From NIB,
コードだと, translatesAutoresizingMaskIntoConstraintsは鍵になりそうです。

ContentSize

こちらの方は解決策を書いてらっしゃる方も多いです。
viewDidLayoutSubviewsでコンテンツサイズを指定するといった方法でしょうか(stackoverflow)

UIScrollViewのSubViewにframeを指定しても, 全部左端にいく

Appleさんによると(こちら),
constraintをきちんと設定するとのこと(Appleのサンプルは1ページ分なのでいまいちなんだよ).
上の方に書いてある内容でなんとかなったのでそれを…

サンプル

省略しています, subViewControllersには, ViewControllerを直接叩き込んでいるNSMutableArrayです


self.scrollView = [[UIScrollView alloc] initWithFrame:frame];
self.scrollView.pagingEnabled = YES;
//self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollView setScrollEnabled:YES];
[self.scrollView setShowsHorizontalScrollIndicator:YES];
[self.scrollView setShowsVerticalScrollIndicator:NO];
[self.scrollView setHidden:NO];
self.scrollView.delegate = self;

double width = self.scrollView.frame.size.width;

self.scrollView.contentSize = CGSizeMake(width * [self.subViewControllers count], self.scrollView.frame.size.height);
UIView *contentView = [[UIView alloc]
initWithFrame:CGRectMake(0,0,self.scrollView.contentSize.width,self.scrollView.contentSize.height)];

for ( int i=0; i < [self.subViewControllers count]; i++ ) { UIViewController *vc = [self.subViewControllers objectAtIndex:i]; [contentView addSubview:vc.view]; vc.view.translatesAutoresizingMaskIntoConstraints = NO; UIView *uiview = vc.view; NSDictionary* viewDict = NSDictionaryOfVariableBindings(contentView, uiview); NSString *hconstraints = [NSString stringWithFormat:@"H:|-%f-[uiview]-0-|", width * i]; [contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:hconstraints options:0 metrics:0 views:viewDict]]; [contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[uiview]|" options:0 metrics:0 views:viewDict]]; } [self.scrollView addSubview:contentView]; [self.view addSubview:self.scrollView]; [/cpp] 何をやっているかというと, UIScrollViewと, その中につくるUIViewContollerの間に, ContentViewと称する, UIViewを挟んでいます contentSizeをこれで確実に確定させます constraintは実際のviewの大きさがないとエラーになるので, 各pageのviewはこのcontentViewに押し込みます 各viewに対して, leftのconstraintをかけますこれにより, contentViewに正しい位置で配置できます あとは, contentViewをScrollViewに押し込みます ひとつポイントなのが, translatesAutoresizingMaskIntoConstraints, InterfaceBuilderでweakリファレンスしたときは, YESじゃないと
うまくいかなかった

このあたりはまだまだわからないことが多いです。