mixi for iPad Ver 2.0 リリース記念 iPad 風フォトビューアの作り方
初めまして。11 新卒の田村と申します。
好きな食べ物は卵でございます。
現在は iOS 公式クライアントアプリ開発を行っており、主に mixi for iPad の開発を行っております。
そんなおり、12/14 に mixi for iPad Ver. 2.0 がリリースされましたー!88888
今回のアップデートの目玉機能は
でございます。私はこのフォトビューアの開発を行っておりましたので簡単に宣伝させていただきます。
今回の mixi フォト用フォトビューアは、mixi にアップロードされている写真を iPad の大きな画面で閲覧することができ、更にそこからその写真に対してイイネ、コメントを簡単に行うことができます。iPad ならではのシームレスな操作感を実現しておりますので iPad をお持ちの方は是非お試しください。ダウンロードはこちら
さて、このフォトビューアの操作の中で個人的に非常に気に入っているものがあります。そうです、ビューア下部のサムネイルリストをタップして写真を流す操作です。これは iPad の写真アプリのビューアにも搭載されている機能です。
写真をすらすらと流して閲覧できる操作感がなんとも心地いい。。。
ということで今回は簡易版 iPad 風フォトビューアの実装について簡単に紹介させていただきます。今回は簡易版ということで Landscape モードのみ対応の実装方法となります。
必要なコンポーネント
PhotoViewerSample に必要なコンポーネントは、以下の二つになります。
MainViewController では写真の描画やフリックでのスライド機能をもたせます。
ThumbnailListViewController ではビューア下部のサムネイルリストの描画とタッチイベントを取得します。
MainViewController.h
#import <UIKit/UIKit.h> #import "ThumbnailListViewController.h" @interface MainViewController : UIViewController<ThumbnailListViewControllerDelegate> { UIScrollView * scrollView_; NSArray * imageNameArray_; ThumbnailListViewController * thumbnailListViewController_; } @property (nonatomic, retain) UIScrollView * scrollView_; @property (nonatomic, retain) NSArray * imageNameArray_; @property (nonatomic, retain) ThumbnailListViewController * thumbnailListViewController_; @end
このクラスには、写真をスライドさせるためのUIScrollView、画像のファイル名を持たせるためのNSArray、そして、ThumbnailListViewController のオブジェクトをプロパティとして持たせます。
MainViewController.m
#import "MainViewController.h" @implementation MainViewController @synthesize scrollView_; @synthesize imageNameArray_; @synthesize thumbnailListViewController_; #pragma mark - ThumbnailListViewController delegate -(void)thumbnailListViewControllerDidTouche:(ThumbnailListViewController *)thumbnailListViewController Index:(int)index { //5) 指定の位置までスクロールさせる CGRect rect = CGRectMake(scrollView_.frame.size.width * index, 0, scrollView_.frame.size.width, scrollView_.frame.size.height); [scrollView_ scrollRectToVisible:rect animated:NO]; } #pragma mark - View lifecycle - (void)viewDidLoad { [super viewDidLoad]; //1) 画像配列作成 self.imageNameArray_ = [NSArray arrayWithObjects: @"image1.png", @"image2.png", @"image3.png", @"image4.png", nil]; //2) スクロールビューの設定 self.scrollView_ = [[[UIScrollView alloc] init]autorelease]; [self.scrollView_ setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) ]; [self.scrollView_ setContentSize:CGSizeMake(self.view.frame.size.width * [self.imageNameArray_ count], self.view.frame.size.height) ]; self.scrollView_.pagingEnabled = YES; [self.view addSubview:self.scrollView_]; //3) スクロールビューに画像を描画する for(int i = 0; i < [self.imageNameArray_ count]; i ++){ UIImage * image = [UIImage imageNamed:[self.imageNameArray_ objectAtIndex:i]]; UIImageView * imageView = [[[UIImageView alloc] initWithImage:image] autorelease]; [self.scrollView_ addSubview:imageView]; [imageView setFrame:CGRectMake(self.view.frame.size.width * i, 0, self.view.frame.size.width, self.view.frame.size.height) ]; } //4) サムネイルリスト描画 self.thumbnailListViewController_ = [[[ThumbnailListViewController alloc]initWithImageNameArray:self.imageNameArray_]autorelease]; self.thumbnailListViewController_.delegate_ = self; [self.view addSubview:self.thumbnailListViewController_.view]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return YES; } @endMainViewController の実装部分です。まず ViewDidLoad でレイアウトの実装を行います。 1) では、あらかじめ読み込む画像のファイル名をNSArrayに格納しておきます。
2) でスクロールビューの設定を行います。スクロールビューのサイズは画面のサイズを設定、contentSizeには(写真の枚数 × 画面サイズ)を指定します。また pagingEnabled プロパティを YES に設定することで、フリックするたびにスクロールを止めることが可能になります。
3) では 2) で設定したスクロールビューに画像をのせていきます。2), 3) で以下のような描画を行っております。
4) の部分で、ThumbnailListViewController のインスタンスを生成してMainViewController の上にのせています。ThumbnailListViewController でも画像を使用するので imageNameArray_ を用いて初期化しています。
次に thumbnailListViewControllerDidTouche:Index: メソッドの説明です。
5) の部分では、ThumbnailListViewController のデリゲートメソッドを実装します。ここでは、どのサムネイルをタッチしたのかという情報を受け取って、スクロールビューを対応する写真の位置までスクロールするように実装します。
ThumbnailListViewController.h
#import <UIKit/UIKit.h> #define kThumbnailListViewControllerViewPosy 704 #define kThumbnailListViewControllerViewWidth 1024 #define kThumbnailListViewControllerViewHeight 44 #define kThumbnailImageViewWidth 40 #define kThumbnailImageViewHeight 30 @interface ThumbnailListViewController : UIViewController { NSArray * imageNameArray_; UIView * thumbnailListView_; id delegate_; } @property (nonatomic, retain) NSArray * imageNameArray_; @property (nonatomic, retain) UIView * thumbnailListView_; @property (nonatomic, assign) id delegate_; - (id)initWithImageNameArray:(NSArray*)imageNameArray; @end @protocol ThumbnailListViewControllerDelegate <NSObject> -(void)thumbnailListViewControllerDidTouche:(ThumbnailListViewController*)thumbnailListViewController Index:(int)index; @end
このクラスではサムネイルを表示させるためのUIView, イメージ名の NSArray そして、どのサムネイルがタッチされたかを MainViewController に通知するための delegate をプロパティとして用意します。そして、ThumbnailListViewControllerDelegate protocol を用意します。
ThumbnailListViewController.m
#import "ThumbnailListViewController.h" @implementation ThumbnailListViewController @synthesize imageNameArray_; @synthesize thumbnailListView_; @synthesize delegate_; - (id)initWithImageNameArray:(NSArray *)imageNameArray { self = [super init]; if (self) { self.imageNameArray_ = [NSArray arrayWithArray:imageNameArray]; } return self; } -(void)dealloc { self.imageNameArray_ = nil; self.thumbnailListView_ = nil; [super dealloc]; } #pragma mark - touch event -(void)getToucheAreaByCGPoint:(CGPoint)point { //12) どのサムネイルがタッチされているかを計算 float touchePosX = point.x - self.thumbnailListView_.frame.origin.x; int index; if(touchePosX < 0){ index = 0; }else if(touchePosX > self.thumbnailListView_.frame.size.width){ index = [self.imageNameArray_ count] - 1; }else{ index = floor(touchePosX / kThumbnailImageViewWidth); } if([self.delegate_ respondsToSelector:@selector(thumbnailListViewControllerDidTouche:Index:)]){ [self.delegate_ thumbnailListViewControllerDidTouche:self Index:index]; } } -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { //9) タッチイベント開始を取得 CGPoint point = [[touches anyObject] locationInView:self.view]; [self getToucheAreaByCGPoint:point]; } -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { //10) ドラッグイベントを取得 CGPoint point = [[touches anyObject] locationInView:self.view]; [self getToucheAreaByCGPoint:point]; } -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { //11) タッチ終了イベントを取得 CGPoint point = [[touches anyObject] locationInView:self.view]; [self getToucheAreaByCGPoint:point]; } #pragma mark - View lifecycle - (void)viewDidLoad { [super viewDidLoad]; //6) サイズの設定 [self.view setFrame:CGRectMake(0, kThumbnailListViewControllerViewPosy, kThumbnailListViewControllerViewWidth, kThumbnailListViewControllerViewHeight)]; self.view.backgroundColor = [UIColor blackColor]; //7) サムネイル画像を描画するサムネイルリストビューを生成、レイアウト self.thumbnailListView_ = [[[UIView alloc] init] autorelease]; self.thumbnailListView_.backgroundColor = [UIColor greenColor]; [self.thumbnailListView_ setFrame:CGRectMake(0, 0, kThumbnailImageViewWidth * [self.imageNameArray_ count], kThumbnailImageViewHeight)]; [self.view addSubview:self.thumbnailListView_]; [self.thumbnailListView_ setCenter:CGPointMake(self.view.frame.size.width/2, self.view.frame.size.height/2)]; //8) サムネイルリストビューの上に書く画像を描画 for(int i = 0; i < [self.imageNameArray_ count]; i ++){ UIImage * image = [UIImage imageNamed:[self.imageNameArray_ objectAtIndex:i]]; UIImageView * thumbnailImageView = [[[UIImageView alloc] initWithImage:image] autorelease]; [self.thumbnailListView_ addSubview:thumbnailImageView]; [thumbnailImageView setFrame:CGRectMake(kThumbnailImageViewWidth * i, 0, kThumbnailImageViewWidth, kThumbnailImageViewHeight)]; } } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return YES; } @endThumbnailListViewController の実装部分です。ViewDidLoad でレイアウトの実装を行います。 6) では、自分自身のサイズを設定しています。
7) でサムネイル画像を描画するための thumbnailListView を生成し、自身の view の中央に設置します。
8) では、7) で生成したビューに画像をのせていきます。
9), 10), 11) では ThumbnailListViewController 上で起きた各種タッチイベントを取得し、その座標を getToucheAreaByCGPoint: メソッドに渡しています。
12) ではタッチイベントで受け取った x座標から、どのサムネイルにタッチしているかを計算して、デリゲートメソッドにその写真のインデックスを渡しています。計算方法は下の図のように、thumbnailListView より左ならインデックスは 0、右なら最後のインデックス、 thumbnailListView の中ならサムネイル画像のサイズを用いて何枚目か割り出します。
実装方法は以上となります。
まとめ
今回は簡易版フォトビューアの実装方法について紹介させていただきました。このように、意外とシンプルな実装でフォトビューアを実現できることがお分かりいただけたと思います。 mixi for iPad Ver. 2.0 ではこのビューアを通じて、たくさんの友人とコミュニケーションをとっていただけるようになっておりますので、是非お試しください。今後の mixi for iPad のアップデートにもご期待ください!