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;
}
@end
MainViewController の実装部分です。まず 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;
}
@end
ThumbnailListViewController の実装部分です。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 のアップデートにもご期待ください!


