LoginSignup
77
80

More than 5 years have passed since last update.

UICollectionViewをジェスチャーで拡大縮小したい(iOS7〜)

Last updated at Posted at 2014-02-11

iOS7から、UICollectionViewのレイアウトを「アニメーションしながら」変更するために、以下の2種類のAPI群が追加されています。

  • タップなどでアニメーションする場合
    • 途中のコントロールが効かない代わりに簡単に使える
    • setCollectionViewLayout:animated:(iOS6から)
    • setCollectionViewLayout:animated:completion:(iOS7から)
  • ジェスチャーなどでアニメーションする場合
    • 途中のコントロールが可能で、「つまんで拡大縮小」といった事が出来る
    • startInteractiveTransitionToCollectionViewLayout:completion: (iOS7から)
    • finishInteractiveTransition(iOS7から)
    • cancelInteractiveTransition(iOS7から)

今回、ピンチジェスチャーでUICollectionViewを拡大縮小したかったので、startInteractiveTransitionToCollectionViewLayout:completion:なAPIを使って実装しました。

サンプルコード

Github

video

処理の流れ

UICollectionViewのinteractiveTransitionとジェスチャーを組み合わせ、以下のような流れで処理が進みます。

  • ジェスチャーの開始
    • 次に表示するUICollectionViewLayoutオブジェクトを生成
    • startInteractiveTransitionToCollectionViewLayout:completion:でTransitionを開始
  • ジェスチャーの状態が変更
    • PinchGestureの場合scaleの値がとれるので、これを元に0〜1の進捗(Progress)を計算し、UICollectionViewTransitionLayoutのtransitionProgressにセットする
    • このprogressに応じて、元のレイアウトと新しいレイアウトの間の状態が自動で計算され、表示される
  • ジェスチャーが終了
    • progressの値に応じて、finishInteractiveTransitionもしくはcancelInteractiveTransitionを呼び出す
    • ジェスチャーを一時停止する(B)
  • (隙間時間が発生)(A)
  • アニメーションの完了
    • start時にしていたcompletionブロックが呼び出される
    • ジェスチャーを再開する(B)

ここで注意するのは、ジェスチャーの終了からアニメーションの完了までに隙間時間(A)がある事です。progressが0.6等の半端な場合にfinishInteractiveTransitioncancelInteractiveTransitionを呼び出すと、progress1.0になるまでアニメーションして(体感1秒程度かかるときがある)、その後にcompletionブロックが呼び出されます。
この隙間時間に次のtransitionを開始しようとするとクラッシュします。
次のTransitionが始まったら、隙間時間をすっ飛ばして次に行きたい所ですが、自分にはそのやり方がわからなかったので、ジェスチャーを一時停止する事にしました(B)。

ソースコードの抜粋

ジェスチャー部分だけ抜粋します。 色々なコードを逃がしているので、全体像はGithubを見てください。

#define kPAMProgressThreshold 0.5
-(void)pinchAction:(UIPinchGestureRecognizer *)gesture
{
    switch(gesture.state){
        case UIGestureRecognizerStateBegan:
        {
            NSLog(@"begin scale=%f",gesture.scale);
            // 拡大なのか縮小なのかを記録しておく。
            // これをしておかないと、拡大で開始して途中で縮小したりするとおかしな事になる。
            self.zoomingStatus = gesture.pam_zoomStatus;

            // Transitionする先のLayoutを用意
            NSUInteger nextItemCount = [self nextHoraizontalItemCount];
            UICollectionViewLayout *nextLayout=[UICollectionViewFlowLayout layoutWithHorizontalItemCount:nextItemCount];

            // Transitionの開始
            [self.collectionView startInteractiveTransitionToCollectionViewLayout:nextLayout
                                                                       completion:^(BOOL completed, BOOL finish) {
                                                                           NSLog( @"completion");
                                                                           // Transitionの完了時にジェスチャーを止めるので、ここで再開
                                                                           [self enableGesture];
                                                                       }];
        }
            break;
        case UIGestureRecognizerStateChanged:
            // Transitionの進捗(progress)を0.0〜1.0で更新
            self.transitionLayout.transitionProgress = [gesture pam_transitionProgressWithZoomStatus:self.zoomingStatus];
            NSLog( @"transitionProgress=%f",self.transitionLayout.transitionProgress);
            break;
        case UIGestureRecognizerStateEnded:
            // Transitionを完了
            if( self.transitionLayout.transitionProgress > kPAMProgressThreshold ){
                [self.collectionView finishInteractiveTransition];
                self.currentHoraizontalItemCount = [self nextHoraizontalItemCount];
            }else{
                [self.collectionView cancelInteractiveTransition];
            }
            // 最後のアニメーションが終わるまでジェスチャーを停止
            [self disableGesture];
            break;
        default:
            break;
    }
}

他のアニメーション

今回は1つのUICollectionViewControllerの中でレイアウトを変更しましたが、UIViewController間でのアニメーションも可能なようです。WWDC 2014のビデオ(要ログイン)の中の「Custom Transitions Using View Controllers」にいろいろ紹介されています。なかなかややこしそうですが、やれる事が増えそうです。

77
80
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
77
80