UIScrollView - ページスクロールで空白を挟む

2010年9月21日火曜日 | Published in | 2 コメント

このエントリーをはてなブックマークに追加

UIScrollView.pagingEnabled = YES とするとページスクロールが可能になる。この場合、写真同士がぴったりとくっついたようになる。

しかし標準の写真アプリだとフリックした時、写真と写真の間に黒い空白(40ピクセル)が入る。一工夫しているようだ。

写真アプリの方が見やすい。これを真似してみよう。


スペースを入れる


通常の UIScrollView ではこんな感じで内部のビューがぴったりと配置されている。

そこで SPACE_WIDTH(40ピクセル)分だけ間を開けてみた(実際にはビューの両側に SPACE_WIDTH/2.0分開けてある)。

1ページ毎に異なった色で塗りつぶしてスクロールが確認できるサンプルアプリを作ってみた。
初期状態。

フリックすると隙間(灰色)が見える。
ページスクロールが完了したところ。SPACE_WIDTHの分だけずれてる。
スクロールを繰り返すとズレ幅が大きくなっていく。

多分こんなふうになっている。
フリックすると frameの大きさだけスクロールされている。
だからズレる。

うーむ。


UIScrollViewの幅を広げる


リファレンスUIScrollView - pagingEnabledによればページスクロールは UIScrollViewの bounds が単位になると書いてある。
If the value of this property is YES, the scroll view stops on multiples of the view bounds when the user scrolls. The default value is NO.

ということは bounds の幅を SPACE_WIDTH分だけ広げてやればいいのでは?

そこでこんな風にしてみた。
scrollView.frame を (x=0, width=320) から (x=-SPACE_WIDTH/2, wdith=320+SPACE_WIDTH) とした。つまり可視範囲をはみ出して設定した。これによって bounds の幅が 320+SPACE_WIDTHとなり、ページスクロール時にスペースを考慮してスクロールが起こるようになるはず。


実装


実装してみよう。まずカスタムビューを定義しておく。
@interface CustomView : UIView {
 UIColor* color;
}
@end

初期化時にランダムもどきな色を決めてその色で塗りつぶす。
@implementation CustomView

- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        // Initialization code
  CGFloat red = (rand()%255) / 255.0;
  CGFloat green = (rand()%255) / 255.0;
  CGFloat blue = (rand()%255) / 255.0;
  color = [UIColor colorWithRed:red
        green:green
         blue:blue
        alpha:1.0];
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
 
 CGRect rect1 = CGRectMake(0, 0, 320, 460);
 CGContextRef context = UIGraphicsGetCurrentContext();
 
 [color set];
 CGContextFillRect(context, rect1);
 [[UIColor whiteColor] set];
 CGContextSetLineWidth(context, 5);
 CGContextStrokeRect(context, rect1);
}


次にスクロール処理のメイン。
@interface ScrollViewPagingViewController : UIViewController  {

 UIScrollView* scrollView;
}
@property (nonatomic, retain) IBOutlet UIScrollView* scrollView;
@end

5つの CustomViewを UIScrollView内に配置してページスクロールさせる。
#define SPACE_WIDTH 40
#define NUMBER_OF_VIEWS 5
- (void)viewDidLoad {
    [super viewDidLoad];

 CGRect scrollViewFrame = self.scrollView.frame;
 scrollViewFrame.origin.x -= SPACE_WIDTH/2;
 scrollViewFrame.size.width += SPACE_WIDTH;
 self.scrollView.frame = scrollViewFrame;
 self.scrollView.contentSize = CGSizeMake((320+SPACE_WIDTH)*NUMBER_OF_VIEWS, 460);
 self.scrollView.pagingEnabled = YES;

 CGFloat x = 0;

 for (int i=0; i < NUMBER_OF_VIEWS; i++) {
  
  // left space
  x += SPACE_WIDTH/2.0;

  // content
  CGRect rect = CGRectMake(x, 0, 320, 460);
  CustomView* view = [[[CustomView alloc] initWithFrame:rect] autorelease];
  [self.scrollView addSubview:view];
  x += rect.size.width;

  // right space
  x += SPACE_WIDTH/2.0;
 }
}
ポイントは、UIScrollViewの frameを可視範囲をはみ出すように設定していることと、CustomViewの両側に SPACE_WIDTH/2.0 分のスペースをいれていること。


さて実行してみよう。まず初期画面。

フリックすると灰色の空白が確認できる。

ページスクロール終了。ぴったりと意図した境界で止まる。
スクロールを繰り返してもズレは起きない。


ソースコード


GitHubからどうぞ。
ScrollViewPaging at 2010-09-21 from xcatsan's iOS-Sample-Code - GitHub

- - - -
わかってみたら簡単だったが、最初は scrollViewDidEndDecelerating: を使って強制的に位置を補正したりなんかしていた(これだと計算が面倒)。

Responses

  1. KatokichiSoft says:
    2010年10月6日 16:08

    この手の話として2つ記事がありましたので、ご参考までに紹介しておきます。

    http://blog.sallarp.com/iphone-ipad-appstore-like-uiscrollview-with-paging-and-preview/

    https://devforums.apple.com/message/230220

  2. KatokichiSoft says:
    2010年10月6日 16:08

    この手の話として2つ記事がありましたので、ご参考までに紹介しておきます。

    http://blog.sallarp.com/iphone-ipad-appstore-like-uiscrollview-with-paging-and-preview/

    https://devforums.apple.com/message/230220

  3. xcatsan says:
    2010年10月7日 9:02

    KatokichiSoftさん、情報どうも。
    とても参考になりました。
    scrollView.clipsToBounds=NO は思いつかなかった。ちょっと試してみたい。

  4. xcatsan says:
    2010年10月7日 9:02

    KatokichiSoftさん、情報どうも。
    とても参考になりました。
    scrollView.clipsToBounds=NO は思いつかなかった。ちょっと試してみたい。

Leave a Response

人気の投稿(過去 30日間)