ぼりぼり農園

iPhoneアプリ開発しながらObjective-CとPerlとLinuxとネタ集め。家に大きめの机欲しい。あとイス。

【Objective-C】UIScrollViewで余白を活かしたページングを実装する裏ワザ

下記の様な、地図上でスポットを探すアプリみたいにUIScrollViewでラベルを横一列に並べた時のページングの時に、余白を利用してエレガントに実装するのがうまくいかず悩んだので解決法メモ。もっといい方法というか正攻法等あればどなたか教えてもらえると嬉しいです。コードは下に記載。

やりたいこと

こんな感じのアプリ画面を作りたいとして。
UIScrollView01

  1. ScrollViewでページングを量産する
  2. 各ページングするScrollView同士の間に余白を取る
  3. 少し前後のScrollViewが見切れるようにする
  4. 見切れる範囲は画面一杯でなく特定のView内に限定する

何px移動するかをちゃんと割り出す

UIScrollView02
考えるべきは、「コンテンツがページングしてどう見えるか」ではなくて、「1ページあたり何px移動するのか」

今回で言えば、1ページングする毎に
「コンテンツの274px」+「余白の4px」=278px
移動していますね。

でもここまでは考えると思うんです。

陥りがちなのが、「1ページ目は左に余白がないので少なめで、2ページ目以降は追加したコンテンツの余白分足した分だけ移動するのか…」などと考え始めると確実に死にます。いくらページングしたくてもうまくいかないので、そのうちカーズのように考えるのをやめる事になります。

余白を含めてスライド領域として考える

じゃあどうすればいいのだ!となりますが、ここで重要なのは、目に見えるコンテンツではなく、余白も含めてコンテンツだと考えることです。自分はこの境地に至るまで情けない事に2日程かかりました。
UIScrollView03
上図のように考えれば答えが見えてきます。

ページングするViewはあくまで透明なViewで、見えているコンテンツはその上にただ余白を空けて乗っかってるだけ

という事が見えてくるはず。意外と簡単なのではないか。
余白なんて考えなくていいんや!

実装

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor redColor];
    
    // 地図View
    UIView *mapView = [[UIView alloc] init];
    mapView.frame = CGRectMake(10, 100, 300, 400);
    mapView.backgroundColor = [UIColor greenColor];
    [self.view addSubview:mapView];
    
    // スクローラーを載せるラベル設定(余白を含む透明のビュー)
    UIView *scrollerRootView = [[UIView alloc] init];
    scrollerRootView.frame = CGRectMake(0, 300, 300, 54);
    [mapView addSubview:scrollerRootView];
    scrollerRootView.backgroundColor = [UIColor clearColor];  // 透明だけど使えるViewとして存在させる(本当はこの行は不要)
    scrollerRootView.clipsToBounds = YES; //このラベルをはみ出た画像は見えないようにする
    
    // スクローラーの設定
    UIScrollView *scroller = [[UIScrollView alloc] init];
    scroller.frame = CGRectMake(11, 0, 278, 54);
    scroller.clipsToBounds = NO; // スクローラーをはみ出ても画像が見える様にする
    scroller.bounces = NO;  // 弾ませない
    scroller.showsHorizontalScrollIndicator = NO;  // スクロールバーを出さない
    scroller.pagingEnabled = YES; // ページングを許可
    [scrollerRootView addSubview:scroller];
    
    
    // スクローラーにコンテンツを載せる(5ページ分)
    for (int i = 0; i < 5; i++) {
        UIView *scrollerView = [[UIView alloc] init];  //
        float color = (i + 1.0) / 5.0;
        scrollerView.backgroundColor = [UIColor colorWithRed:color green:color blue:color alpha:1]; //ページごとに色を変えてみる
        NSLog(@"%f",color);
        [scroller setContentSize:CGSizeMake((274+2+2)*(i+1), 54)]; // スクロールする全体の範囲
        scrollerView.frame = CGRectMake(2+(274+2+2)*(i), 0, 274, 54); // ページングする下地のView分移動して配置
        [scroller addSubview:scrollerView];
    }
    
    // スクローラーの初期位置を1ページ目の位置にする
    [scroller setContentOffset:CGPointMake(0, 0) animated:YES];

}

ソース一式はGitHubに上げてみました

GitHub緊張。
変な所、改善点等あればご指摘いただけると狂い悶えるのだ...喜びでなッ!!
UIScrollViewPagingDemo

iPhoneアプリ開発のコツとツボ35

iPhoneアプリ開発のコツとツボ35