iPhoneホームのようなページング

2010/09/11

iPhoneホームのようなページングが、かなりお手軽に作成できるのでちょっとびっくり。 iphone

基本的にはUIScrollViewだけで完結しますが、UIPageControlで現在のページ状況を表示できます。 ちなみにUIPageControlはUIViewの子です。 iphone

ポイントはUIScrollViewのframeのサイズを利用して横スクロールさせる、つまり映画のフレーム方式です。 Flash制作者の人ならよく使う技ですけど、ごり押しコードでなくもっとシステマティックですw

表示するページコンテンツをいつ追加するかはアプリによると思いますが、 とりあえず全ページ作られた状態でスクロールする方法で。

HomeViewController.h

まず、定義から。

@interface HomeViewController : UIViewController {
    UIScrollView *scrollView;
    UIView *pageView;
    UIPageControl *pageControl;
}

@property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
@property (nonatomic, retain) IBOutlet UIView *pageView;
@property (nonatomic, retain) IBOutlet UIPageControl *pageControl;
@end

UIViewControllerのViewにscrollViewとpageControlを追加します。 さらにscrollViewでページングで表示するViewをpageViewとしました。 あとはスクロールの機能を使うので、UIScrollViewDelegateの追加を。

HomeViewController.xib

(1)scrollViewでページングで表示するView(pageView)を追加する iphone ※PageViewは、IBOutlet *pageViewにバインド

このViewに1ページずつコンテンツを作ります。 サイズは320px/1ページになるかと思います。

(2) ViewにUIScrollViewとUIPageControlを配置する iphone ※ScrollViewは、IBOutlet *scrollViewにバインド ※PageControlは、IBOutlet *pageControlにバインド

(3) UIScrollViewのdelegateをFile's Ownerにバインドする iphone

delegateしておくことで自動的にscrollViewDidScrollが呼ばれます。 ちなみに、UIScrollViewのDelegateメソッドを調べると、

- (void)scrollViewDidScroll:(UIScrollView *)scrollView;                                               // any offset changes
- (void)scrollViewDidZoom:(UIScrollView *)scrollView __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_2); // any zoom scale changes

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;                              // called on start of dragging (may require some time and or distance to move)
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate; // called on finger up if user dragged. decelerate is true if it will continue moving afterwards

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView;   // called on finger up as we are moving
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;      // called when scroll view grinds to a halt

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView; // called when setContentOffset/scrollRectVisible:animated: finishes. not called if not animating

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;     // return a view that will be scaled. if delegate returns nil, nothing happens
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_2); // called before the scroll view begins zooming its content
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale; // scale between minimum and maximum. called after any 'bounce' animations

- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView;   // return a yes if you want to scroll to the top. if not defined, assumes YES
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView;      // called when scrolling animation finished. may be called immediately if already at top

これで、ズームもいけちゃうっぽい!?

次に実装です。

HomeViewController.m

#import "HomeViewController.h"

@implementation HomeViewController

@synthesize scrollView;
@synthesize pageView;
@synthesize pageControl;

- (void)viewDidLoad {
    [super viewDidLoad];

    scrollView.pagingEnabled = YES;  
    scrollView.contentSize = CGSizeMake(640, 0);
    scrollView.showsHorizontalScrollIndicator = NO;  
    scrollView.showsVerticalScrollIndicator = NO;  
    scrollView.scrollsToTop = YES;
    
    pageControl.numberOfPages = 2;
    pageControl.currentPage = 0;

    [scrollView addSubview:pageView];
}

- (void)scrollViewDidScroll:(UIScrollView *)sender {
    CGFloat pageWidth = scrollView.frame.size.width;  
    pageControl.currentPage = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;  
} 
@end

実は

scrollViewのcontentSizeの設定と、pagingEnabledを有効する

だけでページングできてしまうのです。素晴らしい! 始めはこれを知らずに、scrollViewの位置とかで計算しようとしてましたw

UIScrollView scrollViewDidScrollを利用して、pageControlに現在のページ情報を設定します。 scrollViewの幅を計算して出してるところが力技っぽいけど。 将来的には、ページング周りのAPIが充実してくれるとうれしいですね。 (実はもうあったり!?)