Skip to content

Latest commit

 

History

History
180 lines (139 loc) · 6.55 KB

CardViewAnimation.md

File metadata and controls

180 lines (139 loc) · 6.55 KB

CardViewAnimation

첫번째로, 애니메이션 효과를 줄 xib view를 생성하고 CardViewController에 IBOutlet으로 연결해준다.

스크린샷 2020-05-02 오후 1 12 38

스크린샷 2020-05-02 오후 1 13 17

그 다음으로 실행에 필요한 것들을 설정해준다.

    enum CardState {
        case expanded
        case collapsed
    }	// card view의 상태
    
    // xib 참조
    var cardViewController: CardViewController!
    // 애니메이션 효과
    var visualEffectView: UIVisualEffectView!
    
    let cardHeight: CGFloat = 600
    let cardHadleAreaHeight: CGFloat = 65
    
    var cardVisible = false
    var nextState: CardState {
        return cardVisible ? .collapsed : .expanded
    }
    
	  // 실행할 모든 애니메이션을 배열로 담아놓는다.
    var runningAnimations = [UIViewPropertyAnimator]()
    var animationProgressWhenInterrupted: CGFloat = 0

그 다음, card view를 세팅하는 함수를 만들어준다.

    func setupCard() {
      	// Add Visual Effects View
        visualEffectView = UIVisualEffectView()
        visualEffectView.frame = self.view.frame
        self.view.addSubview(visualEffectView)
        
      	// Add CardViewController xib to the bottom of the screen
        cardViewController = CardViewController(nibName: "CardViewController", bundle: nil)
        self.addChild(cardViewController)
        self.view.addSubview(cardViewController.view)
        
        cardViewController.view.frame = CGRect(x: 0, y: self.view.frame.height - cardHadleAreaHeight, width: self.view.bounds.width, height: cardHeight)
      	// clipping bounds so that the corners can be rounded
        cardViewController.view.clipsToBounds = true
        
        // Add tap and pan recognizers
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.handleCardTap(recognizer:)))
        let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(ViewController.handleCardPan(recognizer:)))
        
        cardViewController.handleArea.addGestureRecognizer(tapGestureRecognizer)
        cardViewController.handleArea.addGestureRecognizer(panGestureRecognizer)
    }
    @objc
    func handleCardTap(recognizer: UITapGestureRecognizer) {
        
    }
    
    @objc
    func handleCardPan(recognizer: UIPanGestureRecognizer) {
        switch recognizer.state {
        // 클릭
        case .began:
            startInteractiveTransition(state: nextState, duration: 0.9)
        // 변화가 있을 때
        case .changed:
            let translation = recognizer.translation(in: self.cardViewController.handleArea)
            var fractionComplete = translation.y / cardHeight
            fractionComplete = cardVisible ? fractionComplete : -fractionComplete
            updateInteractiveTransition(fractionCompleted: fractionComplete)
        // 움직임이 끝났을 때
        case .ended:
            continueInteractiveTransition()
        default:
            break
        }
    }

애니메이션이 진행될 때의 transition을 모두 설정해준다.

    func animationTransitionIfNeeded(state: CardState, duration: TimeInterval) {
        if runningAnimations.isEmpty {
            let frameAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 1) {
                switch state {
                // 카드를 위로 올릴 때
                case .expanded:
                    self.cardViewController.view.frame.origin.y = self.view.frame.height - self.cardHeight
                // 카드를 아래로 내릴 때
                case .collapsed:
                    self.cardViewController.view.frame.origin.y = self.view.frame.height - self.cardHadleAreaHeight
                }
            }
            
            frameAnimator.addCompletion { _ in
                self.cardVisible = !self.cardVisible
                self.runningAnimations.removeAll()
            }
            
            frameAnimator.startAnimation()
            runningAnimations.append(frameAnimator)
            
            // 카드 뷰에 corner radius 효과
            let cornerRadiusAnimator = UIViewPropertyAnimator(duration: duration, curve: .linear) {
                switch state {
                // 카드를 위로 올릴 때
                case .expanded:
                    self.cardViewController.view.layer.cornerRadius = 12
                // 카드를 아래로 내릴 때
                case .collapsed:
                    self.cardViewController.view.layer.cornerRadius = 0
                }
            }
            
            cornerRadiusAnimator.startAnimation()
            runningAnimations.append(cornerRadiusAnimator)
            
          	// 뒷 배경 블러 효과
            let blurAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 1) {
                switch state {
                // 카드를 위로 올릴 때
                case .expanded:
                    self.visualEffectView.effect = UIBlurEffect(style: .dark)	
                // 카드를 아래로 내릴 때
                case .collapsed:
                    self.visualEffectView.effect = nil
                }
            }
            
            blurAnimator.startAnimation()
            runningAnimations.append(blurAnimator)
        }
    }
    
    func startInteractiveTransition(state: CardState, duration: TimeInterval) {
        if runningAnimations.isEmpty {
            // run animations
            animationTransitionIfNeeded(state: state, duration: duration)
        }
        for animator in runningAnimations {
            animator.pauseAnimation()
          	// view를 올릴 때 흐리게 처리하는 정도 : fractionComplete
            animationProgressWhenInterrupted = animator.fractionComplete
        }
    }
    
    func updateInteractiveTransition(fractionCompleted: CGFloat) {
        for animator in runningAnimations {
            animator.fractionComplete = fractionCompleted + animationProgressWhenInterrupted
        }
    }
    
    func continueInteractiveTransition() {
        for animator in runningAnimations {
            animator.continueAnimation(withTimingParameters: nil, durationFactor: 0)
        }
    }

실행 결과

14주차