2010年7月6日火曜日

UIScrollView - フリックで画像(ページ)をめくる

UIScrollViewを使い、指でフリックしてめくっていく簡易的な画像ビューアを作ってみた。

画像サンプル


8枚ほどの検証用画像を用意した(320x460ピクセル)。

画像はここから拝借した。
夜景 - フリー写真素材(無料壁紙画像)Futta.NET


実装


まずスクロール対象のビューを用意する。これは前回のコード(ImageView)をそのまま流用して単純に8枚の画像を横にならべてみた (全体で 2560x460ピクセル)。

[前回] Cocoaの日々: UIScrollView - サムネイル画像を並べて指でスクロールさせる


UIScrolViewの設定も基本的には前回と同じ。今回はこれに Paging設定を追加する。
self.scrollView.contentSize = imageView.bounds.size;  // ビューのサイズを指定
[self.scrollView addSubview:imageView]; // ビューの追加

// new stuffs
self.scrollView.pagingEnabled = YES;
self.scrollView.showsHorizontalScrollIndicator = NO;// 横スクロールバー非表示
self.scrollView.showsVerticalScrollIndicator = NO; // 縦スクロールバー非表示
self.scrollView.scrollsToTop = NO; // ステータスバーのタップによるトップ移動禁止

UIScrollView.paginEnabled = YES とすることで、スクロールの単位が画面横幅(320ピクセル)となる。指を離すと必ず左右どちらかかの画像が表示されるまでスクロールされる。
こんな感じ。
右から左へフリックすると

右へスクロールする。指を離すと

右側の画像までスクロールして止まる。


参考情報

Scrolling Using the Paging Mode
UIScrollViewのPaging Modeについての解説。
PageControl
今回のようなページめくりのサンプルコード。参考になる。

11 件のコメント:

  1. こんばんは、とても参考にさせて頂いているのですが、質問させて下さい。
    上記の様に8枚のイメージがスクロールビューに設定されていた場合で
    初期表示で指定ページに移動させておきたい場合は、
    どの様にすればよろしいのでしょうか?
    初心者の質問で申し訳ありませんが、ご回答頂けたら幸いです。

    返信削除
  2. こんにちは。橋口です。

    初期表示で指定ページに移動させておきたい場合は、UIScrollView の contentOffset プロパティもしくは setContentOffset:animated: を使います。UIScrollView は巨大な画像の一部を切り取って表示するような動作を行っていますが、このプロパティでその表示位置を指定することができます。指定ページの表示位置は1ページ当たりの画像の横幅×ページ数で決めることができるのでコードは次のようになります。

    CGPoint offset = CGPointMake(imageWidth * (page - 1), 0);
    [self.scrollView setContentOffset:offset animated:NO];

    ※(page-1)はページ番号が 1始まりの場合です(0始まりなら不要)。

    上記はメソッドの方を使っています。メソッドの場合アニメーション動作が指定できるので、初期表示などアニメーションが不要な場合はメソッドを使うのが良いと思います。毎回アニメーションして構わないという場合はプロパティも利用できます。

    self.scrollView.contentOffset = offset;

    ちなみにアニメーションとは、例えば4ページを指定した場合、1ページ目から4ページ目まで高速でスライドして移動する様子がアニメーションで表示されます。アニメーション無しだと、いきなりそのページが表示されます。

    それでは。

    返信削除
  3. 樋口様、ご回答ありがとうございます。
    いろいろ、ご回答頂いたののですが、
    樋口様の2010/10/22のサンプルコードの様に
    「指定のページを表示するメソッドを追加」することで
    指定ページへ移動が簡単に実現出来ました。
    今後とも、参考にさせて頂きますのでよろしくお願い致します。

    返信削除
  4. こんにちわ、参考にさせて頂いています。

    おわかりであればご教授お願いしたいのですが、フリックした際にプログレッシブJPEGのような、最初ぼやけて次第 にフォーカスが定まる感じの処理は、どのように実装しているのでしょうか。

    返信削除
  5. Kazuki さん、こんばんは。

    > 最初ぼやけて次第 にフォーカスが定まる感じ

    Core Animation のトランジションを使うとそれに近い効果が出せるかもしれません。
    (参考)
    http://cocoadays.blogspot.com/2010/10/uiview-2.html
    http://cocoadays.blogspot.com/2010/10/14.html

    2つのビューを用意する必要がありますが、両方のビューに必ずしもイメージがある必要はなくて、最初にブランクのビューを用意しておき kCATransitionFade を使って目的の画像に切り替えるとジワジワっと出てくる感じが出せるかもしれません。

      第1のビュー(ブランク)
       |
       |kCATransitionFade トランジション
       ↓
      第2のビュー(画像あり)


    参考まで。
    では。

    返信削除
  6. 初めまして。
    お忙しい中、申し訳ありませんが質問よろしいでしょうか?
    色々なサイトを参考にしてScrollViewの練習をしています。
    ScrollViewのFrameサイズですが、下記のようにコードを書いていますが、
    画面下にグレーのスペースができてしまい、フル画面表示されないのはなぜでしょうか?
    ちなみにframeをCGRectMake(0,0,320,480); などにしてもダメでした。
    初歩的な質問で申し訳ありませんが、宜しくお願い致します。

    UIScrollView *scrollView = [[UIScrollView alloc] init];
    scrollView.frame = self.view.bounds;
    scrollView.contentSize = CGSizeMake(self.view.frame.size.width * ああああ, self.view.frame.size.height);

    返信削除
  7. おはようございます。

    > 画面下にグレーのスペースができてしまい、フル画面表示されないのはなぜでしょうか?

    まだわからないのですが、UIScrollView で表示させているビューの種類はなんでしょうか。UIImageView ?そちらの frame はどんな感じでしょう。

    では。

    返信削除
  8. ご返信ありがとうございます。
    下記が全体のコードです。
    ステータスバーを非表示にしているのですが、ちょうどそのステータスバーの幅くらいのスペースが下にできてしまいます。
    宜しくお願い致します。

    UIScrollView *scrollView = [[UIScrollView alloc] init];
    scrollView.frame = self.view.bounds;
    scrollView.contentSize = CGSizeMake(self.view.frame.size.width *kPageNum, self.view.frame.size.height);
    scrollView.pagingEnabled = YES;
    [self.view addSubview:scrollView];
    [scrollView release];

    for (int i=0;i<kPageNum;i++) {
    UIImageView *imageView = [[UIImageView alloc] init];
    imageView.frame = CGRectMake(
    self.view.frame.size.width * i,
    0,
    self.view.frame.size.width,
    self.view.frame.size.height
    );
    imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"%d.jpg",i]];
    imageView.contentMode = UIViewContentModeScaleAspectFit;
    [scrollView addSubview:imageView];
    [imageView release];

    返信削除
  9. こんばんは。

    > ステータスバーを非表示にしているのですが、ちょうどそのステータスバー
    > の幅くらいのスペースが下にできてしまいます。

    なるほど。恐らくステータスバーの高さ(20px)だけ self.view.frame.size.height が欠けているのだと思います。
    iPhoneの画面高さは 480px ですが、self.view の高さは、ステータスバーの高さ20pxを除いた 460px になっています。この高さのまま、ステータスバーを隠すとself.view(高さ460px)はちょうど画面(高さ480px)の一番上にくるので結果として画面下に 20px分の未描画領域が表示されるのだと思います。グレー色は多分ベースにあたる UIWindowの色だと思います。

    この解消方法ですが探してみたら、この問題についてと思われる記事をみつけました。
    参考までにリンクを載せておきます。

    「http://d.hatena.ne.jp/iphone_dev/20081027/1225101937
    ※2009年と古いのですが、コメントに 20pxの理由がかかれていました。

    上記を参考にすると
    self.view.frame = [UIScreen mainScreen].bounds;
    を書けば良さそうです。

    試していないのですが参考にしてみてください。

    ※上記は googleで「uistatusbar 460」をキーワードに探しました。

    解決するといいのですが。
    では。

    返信削除
  10. 上記URLを参考に無事解決しました!
    丁寧なご回答ありがとうございました。
    これからもサイト参考にさせてもらいます!

    返信削除
  11. おはようございます。

    無事に解決できたようで何よりです。
    開発頑張ってください。

    では。

    返信削除