(参考) 無為空間 |タイルビューの挙動確認用サンプル
CATiledLayerとUIScrollViewを組み合わせて、巨大な画像をスムーズにスクロールして表示するサンプルです。
表示する画像はこちらを使用しました。Garden | photo page - everystockphoto
画像の大きさは2448x3264です。
大きな画像を一度に読み込むとメモリが足りなくなるので、あらかじめ小さな単位に分割しておきます。
画像の分割はGraphicConverterなどを使用すると簡単です。
分割した画像を、画面に表示される部分だけ読み込むので、ファイル名を規則的に付けておきます。
GraphicConverterなら、自動的にimage-01-01.jpg, image-01-02.jpg, ...のような名前に自動的に付けてくれます。
今回は、タテ、ヨコそれぞれ10分割にしました。
分割後の画像サイズは245x327です。
まず、表示レイヤーにCATiledViewを使用するビュー(TiledView)を作成します。
+ (Class)layerClass { return [CATiledLayer class]; }
ビュー全体のサイズに、もとの画像サイズを指定します。
タイル1つぶんのサイズに分割後の画像サイズを指定します。
TiledView *tiledView = [[TiledView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 2448.0f, 3264.0f)]; tiledView.tiledLayer.tileSize = CGSizeMake(245.0f, 327.0f);
TiledViewをスクロールビューのサブビューとして設定します。
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 460.0f)]; scrollView.contentSize = tiledView.bounds.size; scrollView.delegate = tiledView; [scrollView addSubview:tiledView];
TiledViewでは、次に表示されるタイルごとにdrawRect:が呼ばれます。
どの位置のタイルなのかを判定して、適切な画像を読み込み、描画します。
- (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); int xmin = CGRectGetMinX(rect); int ymin = CGRectGetMinY(rect); int x = xmin / CGRectGetWidth(rect); int y = ymin / CGRectGetHeight(rect); NSString *fileName = [NSString stringWithFormat:@"image-%02d-%02d.jpg", x + 1, y + 1]; UIImage *image = [UIImage imageNamed:fileName]; [image drawInRect:rect]; }
そのまま動作するサンプルプロジェクトをGitHubに置きました。
kishikawakatsumi's TiledLayerView at master - GitHub
だいたいのコードは下記になります。
#import <UIKit/UIKit.h> #import <QuartzCore/QuartzCore.h> @interface TiledView : UIView <UIScrollViewDelegate> { CATiledLayer *tiledLayer; } @property (nonatomic, readonly) CATiledLayer *tiledLayer; @end @implementation TiledView + (Class)layerClass { return [CATiledLayer class]; } - (CATiledLayer *)tiledLayer { return (CATiledLayer *)self.layer; } - (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGAffineTransform t = CGContextGetCTM(context); int xmin = CGRectGetMinX(rect); int ymin = CGRectGetMinY(rect); int xmax = CGRectGetMaxX(rect); int ymax = CGRectGetMaxY(rect); int x = xmin / CGRectGetWidth(rect); int y = ymin / CGRectGetHeight(rect); NSString *fileName = [NSString stringWithFormat:@"image-%02d-%02d.jpg", x + 1, y + 1]; UIImage *image = [UIImage imageNamed:fileName]; [image drawInRect:rect]; } - (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView { [self setNeedsDisplay]; return NO; } - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { return self; } - (void)dealloc { [tiledLayer release]; [super dealloc]; } @end
#import <UIKit/UIKit.h> #import "TiledView.h" @interface TiledLayerViewController : UIViewController { UIScrollView *scrollView; TiledView *tiledView; } @end @implementation TiledLayerViewController - (void)viewDidLoad { [super viewDidLoad]; tiledView = [[TiledView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 2448.0f, 3264.0f)]; tiledView.tiledLayer.tileSize = CGSizeMake(245.0f, 327.0f); tiledView.tiledLayer.levelsOfDetail = 1; tiledView.tiledLayer.levelsOfDetailBias = 0; scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 460.0f)]; scrollView.contentSize = tiledView.bounds.size; scrollView.maximumZoomScale = 4.0f; scrollView.minimumZoomScale = 0.5f; scrollView.delegate = tiledView; [scrollView addSubview:tiledView]; [self.view addSubview:scrollView]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } - (void)dealloc { [scrollView release]; [tiledView release]; [super dealloc]; } @end