このようにタップするとポップアップして拡大するUIをライブラリ化したので、GitHubにコミットしておきました。

https://github.com/stack3/STPopupFocusImageManager

FacebookやTumblrでお馴染みですが、結構、作るの面倒でしたね、これ・・・。誰かの役に立てれば幸いです。

このライブラリでできること

  • サムネイル画像からポップアップして拡大し、画像を全画面表示する
  • 全画面表示されたあとに、高解像度のオリジナル画像にすり替える
  • ネットワーク画像の取得、画像ビューワーは好きなものを使える

サンプルを見る

まずはサンプルを見てみましょう。GitHubからソースファイルをダウンロードしたら、STPopupFocusImageManagerSample.xcodeprojを開いてビルド&実行。動作するのを確認します。

確認したら、STViewController.mをみてみましょう。

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor whiteColor];

    _image = [UIImage imageNamed:@"ramen200x150.jpg"];
    [_imageButton setImage:_image forState:UIControlStateNormal];
    [_imageButton addTarget:self action:@selector(didTapImageButton:) forControlEvents:UIControlEventTouchUpInside];
}

ここでしているのは、

  • _imageButton(UIButton)に200x150サイズのラーメンのサムネイル画像を表示
  • タップした時にdidTapImageButtonメソッドを呼ぶ

です。

didTapImageButtonの実装は以下のとおりです。

- (void)didTapImageButton:(id)sender
{
    if (_imageManager == nil) {
        _imageManager = [[STPopupFocusImageManager alloc] initWithRootViewController:self];
    }

    NSURL *url = [[NSBundle mainBundle] URLForResource:@"ramen800x600" withExtension:@"jpg"];
    [_imageManager popupFromView:_imageButton
                       fromImage:_image
                originalImageURL:url
               originalImageSize:CGSizeMake(800, 600)];
}
  • _imageManager(STPopupFocusImageManager)オブジェクトが作られていないなら作る
  • リソースからポップアップさせる画像オブジェクトを取得。この画像は800x600で大きめのものである
  • _imageManager#popupFromView***メソッドで画像をポップアップさせる

オリジナル画像はURL指定であることに注目。ネットワークから画像を取得したい場合を考慮して、URL指定にしています。というか、ほとんどのケースではそうだと思いますが・・・今回のようにリソースからオリジナル画像を取得するときは上記のようにNSBundleを使ってファイルURLを生成します。

STPopupFocusImageManagerでは通信関係の処理は実装していません。代わりにSTPopupFocusImageViewControllerを継承して、好きに実装できるようにしてあります。つまり好きなライブラリを使うことができます。

全画面表示した画像はサンプルではズームが効きません。これも画像ビューアを好きに実装できるようにするためです。ズーム機能、ツールバー、キャプションなどアプリによって必要な実装は異なるでしょう。

ネットワーク画像のダウンロード、画像ビューワーのカスタマイズについては後述します。

プロジェクトへの取り込み

自分のプロジェクトで使いたいときは、STPopupFocusImageManager/STPopupFocusImageManagerフォルダにあるソースファイルをプロジェクトへコピーするだけです。

ネットワーク画像のダウンロードと画像ビューワーのカスタマイズ

サンプルのSTPopupFocusImageManagerSample2.xcodeprojを開いてビルド&実行してみましょう。

このサンプルではポップアップして全画面表示後に、オリジナルサイズの画像をダウンロードし、ダウンロード完了したらサムネイルと入れ替えて表示します。また画像のズームもできます。

これらを実現するために、

  • ネットワーク画像のダウンロードはAFNetworking
  • 画像の拡大はnimbusのNIPhotoScrollView

を使っています。

独自のSTPopupFocusImageViewContrtoller(画像ビューワー)を作る

STPopupFocusNetworkImageViewController.hを見てみましょう。

@interface STPopupFocusNetworkImageViewController : STPopupFocusImageViewController

@end

STPopupFocusImageViewControllerを継承しています。

STPopupFocusNetworkImageViewController.mを見てみましょう。viewDidLoadでNIPhotoScrollViewを生成しています。

    CGRect bounds = self.view.bounds;
    NIPhotoScrollView *photoScrollView = [[NIPhotoScrollView alloc] initWithFrame:bounds];
    _photoScrollView = photoScrollView;
    _photoScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
    [self.view addSubview:_photoScrollView];

viewWillAppearでポップアップ元のサムネイル画像を設定しています。

- (void)viewWillAppear:(BOOL)animated
{
    [_photoScrollView setImage:self.fromImage photoSize:NIPhotoScrollViewPhotoSizeThumbnail];
}

viewDidAppearを見てみましょう。

- (void)viewDidAppear:(BOOL)animated
{
    if (_originalImage == nil) {
        NSURLRequest *request = [NSURLRequest requestWithURL:self.originalImageURL];
        NSOperation *operation =
            [AFImageRequestOperation imageRequestOperationWithRequest:request                        success:^(UIImage *image) {
                _originalImage = image;
                [_photoScrollView setImage:_originalImage photoSize:NIPhotoScrollViewPhotoSizeOriginal];
            }];
        [_operationQueue addOperation:operation];
    }
}

まだオリジナルの画像をロードしていなければロードします。 そしてロード完了したら_photoScrollViewにオリジナルの画像として設定します。これでオリジナル画像に切り替わります。

またシングルタップされたときに画像ビューワーを閉じるようにしています。

- (void)handleSingleTap:(UITapGestureRecognizer *)sender
{
    [self dismissPopupFocusImage];
}

閉じたいときはdismissPopupFocusImageを呼びます。dismissViewControllerは使わないでください。

独自のSTPopupFocusImageViewContrtollerが使われるようにする

次にSTViewController.mを見てみましょう。didTapImageButton、つまりサムネイル画像をタップした時の処理は以下のようになっています。

_imageManager = [[STPopupFocusImageManager alloc] initWithRootViewController:self imageViewControllerClass:[STPopupFocusNetworkImageViewController class]];

STPopupFocusImageManagerを生成するとき、第2引数に[STPopupFocusNetworkImageViewController class]を渡しています。これで、STPopupFocusNetworkImageViewControllerが使われるようになります。

独自の画像ビューワーを使う時のまとめ

  • STPopupFocusImageViewControllerを継承して独自のクラスを作る
  • そのクラスを画像表示、ネットワーク画像のダウンロードなどは任意のコードを使って実装する
  • ポップアップを閉じたいときは、STPopupFocusImageViewController#dismissPopupFocusImageメソッドを呼ぶ