Does anyone know what's wrong here ?

I am trying to add an animated card to my app and I wrote the code below in the view controller , but when I run the project I can not interract with the card

CODE :

import UIKit


class HomeViewController: UIViewController {


enum cardState {

case expanded

case collapsed


}

var goalCard:GoalCardViewController!

var visualBlur:UIVisualEffectView!

let cardHeight:CGFloat = 800

let cardHandleHeight:CGFloat = 110

var cardVisible = false

var nextState:cardState {


return cardVisible ? .collapsed : .expanded

}

var runningAnimations = [UIViewPropertyAnimator]()

var animationInProgressWhenInterrupted:CGFloat = 0

override func viewDidLoad() {

super.viewDidLoad()


// Do any additional setup after loading the view.

setUpCard()

}

func setUpCard() {

visualBlur = UIVisualEffectView()

visualBlur.frame = self.view.frame

self.view.addSubview(visualBlur)

goalCard = GoalCardViewController(nibName:"GoalCardViewController", bundle:nil)

self.addChild(goalCard)

self.view.addSubview(goalCard.view)

goalCard.view.frame = CGRect(x: 0, y: self.view.frame.height - cardHandleHeight, width: self.view.bounds.width, height: cardHeight)

goalCard.view.clipsToBounds = true

let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(HomeViewController.handleCardTap(recognizer:)))

let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(HomeViewController.handleCardPan(recognizer:)))

goalCard.handleArea.addGestureRecognizer(panGestureRecognizer)

goalCard.handleArea.addGestureRecognizer(tapGestureRecognizer)


}


@objc

func handleCardTap (recognizer: UITapGestureRecognizer) {


}

@objc

func handleCardPan (recognizer: UIPanGestureRecognizer) {


switch recognizer.state {

case .began:

// Start Transition

startInteractiveTransition(state: nextState, duration: 0.9)

case .changed:

// Update Transition

let translation = recognizer.translation(in: self.goalCard.view)

var fractionComplete = translation.y / cardHeight

fractionComplete = cardVisible ? fractionComplete : -fractionComplete

updateInteractiveTransition(fractionCompleted: 0)

case .ended:

// Continue Transition

func finishInteractiveTransition() {

for animator in runningAnimations {

animator.continueAnimation(withTimingParameters: nil, durationFactor: 0)

}

}

default:

break

}


}

func animateTransitionIfNeeded (state:cardState, duration:TimeInterval) {

if runningAnimations.isEmpty {

let frameAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 1) {

switch state {

case .expanded:

self.goalCard.view.frame.origin.y = self.view.frame.height - self.cardHeight

case .collapsed:

self.goalCard.view.frame.origin.y = self.view.frame.height - self.cardHandleHeight

}

}

frameAnimator.addCompletion { _ in self.cardVisible = !self.cardVisible

self.runningAnimations.removeAll()

}

frameAnimator.startAnimation()

runningAnimations.append(frameAnimator)

let cornerRadiusAnimator = UIViewPropertyAnimator(duration: duration, curve: .linear) {

switch state {

case .expanded:

self.goalCard.view.layer.cornerRadius = 12.0

case .collapsed:

self.goalCard.view.layer.cornerRadius = 12.0

}

}

cornerRadiusAnimator.startAnimation()

runningAnimations.append(cornerRadiusAnimator)

}


}


func startInteractiveTransition (state:cardState, duration:TimeInterval) {

if runningAnimations.isEmpty {

//run animations

animateTransitionIfNeeded(state: state, duration: duration)

}

for animator in runningAnimations {

animator.pauseAnimation()

animationInProgressWhenInterrupted = animator.fractionComplete

}

}

func updateInteractiveTransition (fractionCompleted:CGFloat) {

for animator in runningAnimations {

animator.fractionComplete = fractionCompleted + animationInProgressWhenInterrupted

}

func finishTransition() {

for animator in runningAnimations {

animator.continueAnimation(withTimingParameters: nil, durationFactor: 0)

}

}


}

}

Replies

I formatted the code with code formatter tool (<>) and removed some blank lines.



import UIKit

class HomeViewController: UIViewController {

    enum cardState {
      case expanded
      case collapsed
    }
 
    var goalCard:GoalCardViewController!
    var visualBlur:UIVisualEffectView!
    let cardHeight:CGFloat = 800
    let cardHandleHeight:CGFloat = 110
 
    var cardVisible = false
    var nextState:cardState {
        return cardVisible ? .collapsed : .expanded
    }
 
    var runningAnimations = [UIViewPropertyAnimator]()
    var animationInProgressWhenInterrupted:CGFloat = 0
 
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup  after loading the view.
       setUpCard()
    }
 
    func setUpCard() {
     
        visualBlur = UIVisualEffectView()
        visualBlur.frame = self.view.frame
        self.view.addSubview(visualBlur)
     
        goalCard = GoalCardViewController(nibName:"GoalCardViewController", bundle:nil)
        self.addChild(goalCard)
        self.view.addSubview(goalCard.view)
    
        goalCard.view.frame = CGRect(x: 0, y: self.view.frame.height - cardHandleHeight, width: self.view.bounds.width, height: cardHeight)
     
        goalCard.view.clipsToBounds = true
     
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(HomeViewController.handleCardTap(recognizer:)))
     
        let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(HomeViewController.handleCardPan(recognizer:)))
  
        goalCard.handleArea.addGestureRecognizer(panGestureRecognizer)
        goalCard.handleArea.addGestureRecognizer(tapGestureRecognizer)
    
    }

    @objc func handleCardTap (recognizer: UITapGestureRecognizer) {
          // DONT'T YOU DO ANYTHING HERE ?
          // TEST with a simple print, then later implement what should occur when you tap
          print("Card tapped")
    }
 
    @objc  func handleCardPan (recognizer: UIPanGestureRecognizer) {

        print("Card panned")
        switch recognizer.state {
        case .began:
            // Start Transition
            startInteractiveTransition(state: nextState, duration: 0.9)
        case .changed:
            // Update Transition
            let translation = recognizer.translation(in: self.goalCard.view)
            var fractionComplete = translation.y / cardHeight
            fractionComplete = cardVisible ? fractionComplete : -fractionComplete
            updateInteractiveTransition(fractionCompleted: 0)
        case .ended:
            // Continue Transition
        
           func finishInteractiveTransition() {          // WHAT IS THIS FUNC FOR ? SEEMS IT IS NEVER USED
        for animator in runningAnimations {
              animator.continueAnimation(withTimingParameters: nil, durationFactor: 0)
                             }
                  }
        default:
            break
        }
     
    }
 
 
    func animateTransitionIfNeeded (state:cardState, duration:TimeInterval) {
     
        if runningAnimations.isEmpty {
            let frameAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 1) {
                switch state {
                case .expanded:
                    self.goalCard.view.frame.origin.y = self.view.frame.height - self.cardHeight
                case .collapsed:
                    self.goalCard.view.frame.origin.y = self.view.frame.height - self.cardHandleHeight
                }
            }
            frameAnimator.addCompletion { _ in self.cardVisible = !self.cardVisible
                self.runningAnimations.removeAll()
            }
         
            frameAnimator.startAnimation()
            runningAnimations.append(frameAnimator)
            let cornerRadiusAnimator = UIViewPropertyAnimator(duration: duration, curve: .linear) {
                switch state {
                case .expanded:
                    self.goalCard.view.layer.cornerRadius = 12.0
                case .collapsed:
                    self.goalCard.view.layer.cornerRadius = 12.0
             
                }
             
            }
            cornerRadiusAnimator.startAnimation()
            runningAnimations.append(cornerRadiusAnimator)
        }

    }
 
    func startInteractiveTransition (state:cardState, duration:TimeInterval) {
     
        if runningAnimations.isEmpty {
            //run animations
           animateTransitionIfNeeded(state: state, duration: duration)
        }
     
        for animator in runningAnimations {
            animator.pauseAnimation()
            animationInProgressWhenInterrupted = animator.fractionComplete
        }
     
    }
 
    func updateInteractiveTransition (fractionCompleted:CGFloat) {
     
        for animator in runningAnimations {
            animator.fractionComplete = fractionCompleted + animationInProgressWhenInterrupted
         }
 
        func finishTransition() {        // WHAT IS THIS FUNC FOR ? SEEMS IT IS NEVER USED
         
            for animator in runningAnimations {
                       animator.continueAnimation(withTimingParameters: nil, durationFactor: 0)
                   }
        }
 
     }
}


There are some unclear popints :

- in several places (lines 73, 140) you define func (inside another func) without ever calling it. What is your intent ?

- handleCardTap has noting inside. Is it on purpose ? Test if the func is ever called, with a simple print statement

- Do the same line 60 by adding a print.