回転アニメーション(3)--インタラクティブな回転アニメーション

12214 ワード

拡大した画像をつまんで自動的に縮小して隠す
  • クリックで拡大するビューコンテナにscrollViewがある
  • を拡大することができる.
  • scrollViewのプロキシメソッドでは、スケールの割合
  • を取得できます.
        /**
                 
         
         transform
         a,d            
         tx, ty       
         a,b,c,d          
         */
        func scrollViewDidZoom(scrollView: UIScrollView) {
            print(imageView.transform.a)
        }
    
  • これはブラウザ内部のcellでの傍受であり、インタフェースのスケーリングを制御するには、コントローラがこの設定エージェント方法を行い、コントローラ
  • にスケーリングの割合を提供する必要がある.
      protocol PhotoBrowerCellDelegate: NSObjectProtocol {
          /**
           cell  
         
           - parameter scale:     
           */
          func photoBrowerCellZoom(scale: CGFloat)
      }
    
    weak var photoDelegate: PhotoBrowerCellDelegate?
  • scrollViewプロキシメソッドでスケールを渡す
  •      /**
                 
         
         transform
         a,d            
         tx, ty       
         a,b,c,d          
         */
        func scrollViewDidZoom(scrollView: UIScrollView) {
            print(imageView.transform.a)
            photoDelegate?.photoBrowerCellZoom(imageView.transform.a)
        }
    
  • その後、コントローラにおいてプロキシメソッドが実装されると、コントローラは、ビュースケールがプロキシメソッドにおいてインタラクティブなターンフィールドを実装するためにプロトコルを遵守する必要があることを認識することができる--U I v i e w C o r l erInteractiveTransitioning
  • .
    public protocol UIViewControllerInteractiveTransitioning : NSObjectProtocol {
        public func startInteractiveTransition(transitionContext: UIViewControllerContextTransitioning)
        
        optional public func completionSpeed() -> CGFloat
        optional public func completionCurve() -> UIViewAnimationCurve
    }
    

    このプロトコルの合計3つのメソッドの後、2つはオプションで1つ目を実装するだけです.
  • 変数記録ビューのスケーリングを定義エージェントメソッドに記録するスケーリング
  • .
        func photoBrowerCellZoom(scale: CGFloat) {
            print(scale)
            photoScale = scale
        }
    

    インタラクティブなフィールドエージェントメソッドでアニメーションを作成する
    extension PhotoBrowerController: UIViewControllerInteractiveTransitioning {
        
        //       
        func startInteractiveTransition(transitionContext: UIViewControllerContextTransitioning) {
            //     
            view.transform = CGAffineTransformMakeScale(photoScale, photoScale)
            //      
            view.alpha = photoScale
        }
    }
    
  • 次に、条件呼び出しエージェントメソッドをスケーリングエージェントメソッドでアニメーション
  • として判定する.
    if scale < 1 {
                startInteractiveTransition()
            }
    

    パラメータに伝達される対象は遵守する必要がある--UIViewControllerContextTransitioningプロトコル別分類遵守プロトコル実装プロトコルメソッドポイントプロトコルヘッダファイル実装する必要があるメソッドの多くはすべてコピーして一つ一つ実装する
    // MARK -UIViewControllerContextTransitioning context          
    extension PhotoBrowerController: UIViewControllerContextTransitioning {
        
        // This must be called whenever a transition completes (or is cancelled.)
        // Typically this is called by the object conforming to the
        // UIViewControllerAnimatedTransitioning protocol that was vended by the transitioning
        // delegate.  For purely interactive transitions it should be called by the
        // interaction controller. This method effectively updates internal view
        // controller state at the end of the transition.
        //             
        func completeTransition(didComplete: Bool) {
            //         
            dismissViewControllerAnimated(true, completion: nil)
            
        }
        
        /**
             
         - returns:               
         */
        func containerView() -> UIView? { return view.superview }
        func isAnimated() -> Bool { return true }
        func isInteractive() -> Bool { return true }
        func transitionWasCancelled() -> Bool { return false }
        func presentationStyle() -> UIModalPresentationStyle { return UIModalPresentationStyle.Custom }
        
        func updateInteractiveTransition(percentComplete: CGFloat) {}
        func finishInteractiveTransition() {}
        func cancelInteractiveTransition() {}
        
        func viewControllerForKey(key: String) -> UIViewController? { return self }
        func viewForKey(key: String) -> UIView? { return view }
        func targetTransform() -> CGAffineTransform { return CGAffineTransformIdentity }
        
        func initialFrameForViewController(vc: UIViewController) -> CGRect { return CGRectZero }
        func finalFrameForViewController(vc: UIViewController) -> CGRect { return CGRectZero }
    }
    

    このとき上からインタラクティブな回転場を開始する方法でselfを入力して実行することは可能ですが、バックグラウンドビューはまだ存在します.
        func photoBrowerCellZoom(scale: CGFloat) {
            print(scale)
            photoScale = scale
            //     
            hiddenInterBackView(scale < 1)
            if scale < 1 {
                startInteractiveTransition(self)
            }
        }
        
        private func hiddenInterBackView(hidden: Bool) {
            collectionView.backgroundColor = hidden ? UIColor.clearColor() : UIColor.blackColor()
            saveBtn.hidden = hidden
            closeBtn.hidden = hidden
        }
    

    この時点で縮小アニメーションは実現できますが、再拡大すると境界に白いエッジがあることがわかります.エージェントメソッドで拡大スケールを設定する上で定義したphotosScaleは浮動小数点型です.スケールとalphaを再設定します.
        func photoBrowerCellZoom(scale: CGFloat) {
            print(scale)
            photoScale = scale
            //     
            hiddenInterBackView(scale < 1)
            if scale < 1 {
                startInteractiveTransition(self)
            } else {
                view.transform = CGAffineTransformIdentity
                view.alpha = 1.0
            }
        }
    

    次にズーム後の画像の消失効果を実現します
    プロキシメソッドを追加してコントローラのスケール終了を通知
    protocol PhotoBrowerCellDelegate: NSObjectProtocol {
        /**
         cell  
         
         - parameter scale:     
         */
        func photoBrowerCellZoom(scale: CGFloat)
        
        /**
             
         */
        func photoBrowerCellEndZoom()
    }
    

    scrollViewプロキシメソッドで通知コントローラを呼び出す
        func scrollViewDidEndZooming(scrollView: UIScrollView, withView view: UIView?, atScale scale: CGFloat) {
            
            var offsetX = (scrollView.bounds.width - view!.frame.width) * 0.5
            offsetX = offsetX < 0 ? 0 : offsetX
            
            var offsexY = (scrollView.bounds.height - view!.frame.height) * 0.5
            offsexY = offsexY < 0 ? 0 : offsexY
            
            scrollView.contentInset = UIEdgeInsets(top: offsexY, left: offsetX, bottom: 0, right: 0)
            
            //         
            photoDelegate?.photoBrowerCellEndZoom()
        }
    

    コントローラでズーム終了アニメーションを実現
        func photoBrowerCellEndZoom() {
            if photoScale < 0.8 {
                //     
                completeTransition(true)
            } else {
                //     
                UIView.animateWithDuration(0.25, animations: { 
                    self.view.transform = CGAffineTransformIdentity
                    self.view.alpha = 1.0
                    }, completion: { (_) in
                        self.photoScale = 1.0
                        self.hiddenInterBackView(false)
                })
    
            }
        }
    

    ズーム後に消える
    二縮小して元の位置に戻る
    ブラウザでは、他のピクチャをスライド表示できます.ズームすると、現在のピクチャの元の位置に戻るので、現在のピクチャを記録するindexpathブラウザコントローラは、現在のインデックスを取得する方法を提供します.
        // MARK: -          
        func currentIndexPath() -> NSIndexPath {
            let indexPath = collectionView.indexPathsForVisibleItems().last!
            return indexPath
        }
    

    そして解除ターン中に元の位置に戻すアニメーションを実現fromVCが現在のピクチャブラウザ制御であるpictureViewでindexPathが存在する位置アニメーション設定ピクチャの目標位置を算出する
    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
            
            // MainViewController         
    //        let fromVc = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)
            //        
    //        let toVc = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)
            
            
            if isPresent {
                let toView = transitionContext.viewForKey(UITransitionContextToViewKey)!
                transitionContext.containerView()?.addSubview(presentPicView)
                
    //            toView.alpha = 0.0
                
                let fromRect = pictureView?.cellScreenFrame(picIndexP!)
                let toRect = pictureView?.cellDesFrame(picIndexP!)
                
                presentPicView.frame = fromRect!
                
                UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
    //                toView.alpha = 1.0
                    self.presentPicView.frame = toRect!
                    
                    
                }) { (_) in
                    
                    self.presentPicView.removeFromSuperview()
                    transitionContext.containerView()?.addSubview(toView)
                    
                    //        (API   )
                    //            ,     ,       ,        
                    
                    transitionContext.completeTransition(true)
                }
    
            } else {
                //         fromVc   present            
                
                let fromVc = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as! PhotoBrowerController
                let indexPath = fromVc.currentIndexPath()
                let desRect = pictureView!.cellScreenFrame(indexPath)
                
                let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)!
                UIView.animateWithDuration(transitionDuration(transitionContext), animations: { 
                    fromView.frame = desRect
                    }, completion: { (_) in
                        
                        fromView.removeFromSuperview()
                        //                    
                        transitionContext.completeTransition(true)
                })
    
            }
    
        }
    

    実行結果の発見は私たちが望んでいた終了後の位置ではなく、私たちが前に望んでいた位置ではなくcollectionViewに黒い背景を追加して観察したところ、全体の大きなviewが動いているのは単純な画像が動いているわけではないので、この個別の画像を取ります.
        // MARK: -        
        func currentImageView() -> UIImageView {
            let cell = collectionView.cellForItemAtIndexPath(currentIndexPath()) as! PhotoBrowerCell
            return cell.imageView
        }
    
  • は、表示するピクチャを取得してから、回転場コンテキストのコンテナビューに追加し、fromView、すなわち、ビューに追加された大きなviewリザーバビューから
  • を除去する.
  • アニメーションでピクチャを設定ターゲットframeが完了すると、ピクチャを
  • 削除する.
    //         fromVc   present            
                
                let fromVc = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as! PhotoBrowerController
                let indexPath = fromVc.currentIndexPath()
                let desRect = pictureView!.cellScreenFrame(indexPath)
                
                let showImageView = fromVc.currentImageView()
                transitionContext.containerView()?.addSubview(showImageView)
                
                let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)!
                fromView.removeFromSuperview()
                UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
                    showImageView.frame = desRect
                    }, completion: { (_) in
                        
                        showImageView.removeFromSuperview()
                        //                    
                        transitionContext.completeTransition(true)
                })
    
    

    このとき、画像がジャンプしていきます行き先frame設定下の画像の中心点がfromViewの中心showImageView.center = fromView.centerにあるので、ズーム完了後に中心点に戻って拡大縮小します.ズーム完了後にリセット動作があるのでズーム完了方法に戻ります.
        func scrollViewDidEndZooming(scrollView: UIScrollView, withView view: UIView?, atScale scale: CGFloat) {
            
            if scale >= 0.8 {
                var offsetX = (scrollView.bounds.width - view!.frame.width) * 0.5
                offsetX = offsetX < 0 ? 0 : offsetX
                
                var offsexY = (scrollView.bounds.height - view!.frame.height) * 0.5
                offsexY = offsexY < 0 ? 0 : offsexY
                
                scrollView.contentInset = UIEdgeInsets(top: offsexY, left: offsetX, bottom: 0, right: 0)
            }
        
            //         
            photoDelegate?.photoBrowerCellEndZoom()
        }
    

    この时はすべてそんなに良いように见えますただ1枚のピクチャーを拡大した后にスライドして滑った后のピクチャーは拡大できません前のcellが拡大した后にtransformは変形がなくて回复します
    だから変形を回復する
        private func resetScrollView() {
            scrollView.transform = CGAffineTransformIdentity
            scrollView.contentInset = UIEdgeInsetsZero
            scrollView.contentSize = CGSizeZero
            scrollView.contentOffset = CGPointZero
        }
    

    これでアニメも完成です.