Search code examples
swiftselectoruitapgesturerecognizerfactorization

how to factorize a function including a selector?


I have several views which have the same action. I tried to factorize the function, but it didn't work. here is a part of the code in the ViewController:

class MenuViewController: UIViewController {

    @IBOutlet weak var addButton: FloatingActionButton!
    @IBOutlet weak var viewCALORIES: UIView!
    @IBOutlet weak var viewPROTEINES: UIView!
    @IBOutlet weak var viewLIPIDES: UIView!
    @IBOutlet weak var viewGLUCIDES: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // BoingCalories Protéines Lipides Glucides
        let tapCalories = UITapGestureRecognizer(target: self, action: #selector(boingCALORIES(gesture:)))
        viewCALORIES.addGestureRecognizer(tapCalories)
        
        let tapProteines = UITapGestureRecognizer(target: self, action: #selector(boingPROTEINES(gesture:)))
        viewPROTEINES.addGestureRecognizer(tapProteines)
        
        let tapLipides = UITapGestureRecognizer(target: self, action: #selector(boingLIPIDES(gesture:)))
        viewLIPIDES.addGestureRecognizer(tapLipides)
        
        let tapGlucides = UITapGestureRecognizer(target: self, action: #selector(boingGLUCIDES(gesture:)))
        viewGLUCIDES.addGestureRecognizer(tapGlucides)
        
        }


    @objc private func boingCALORIES(gesture: UITapGestureRecognizer) {
        viewCALORIES.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
        UIView.animate(withDuration: 0.6, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0.4, options: [], animations: { self.viewCALORIES.transform = .identity }, completion: nil)
    }
    
    @objc private func boingPROTEINES(gesture: UITapGestureRecognizer) {
        viewPROTEINES.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
        UIView.animate(withDuration: 0.6, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0.4, options: [], animations: { self.viewPROTEINES.transform = .identity }, completion: nil)
    }
    
    @objc private func boingLIPIDES(gesture: UITapGestureRecognizer) {
        viewLIPIDES.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
        UIView.animate(withDuration: 0.6, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0.4, options: [], animations: { self.viewLIPIDES.transform = .identity }, completion: nil)
    }
    
    @objc private func boingGLUCIDES(gesture: UITapGestureRecognizer) {
        viewGLUCIDES.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
        UIView.animate(withDuration: 0.6, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0.4, options: [], animations: { self.viewGLUCIDES.transform = .identity }, completion: nil)
    }

I've tried some tests, but it fails. So how could i factorize all of this? Thank you


Solution

  • From the UITapGestureRecognizer, you can retrieve the view.

    let view = gesture.view
    

    So you can do:

    @objc private func boingView(gesture: UITapGestureRecognizer) {
        let view = gesture.view
        view.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
        UIView.animate(withDuration: 0.6, 
                       delay: 0,
                       usingSpringWithDamping: 0.3,
                       initialSpringVelocity: 0.4,
                       options: [],
                        animations: { view.transform = .identity },
                        completion: nil)
    }
    

    And to factorize the calls:

    let action = #selector(boingView(gesture:))
    
    let tapCalories = UITapGestureRecognizer(target: self, action: action)
    viewCALORIES.addGestureRecognizer(tapCalories)
            
    let tapProteines = UITapGestureRecognizer(target: self, action: action)
    viewPROTEINES.addGestureRecognizer(tapProteines)
            
    let tapLipides = UITapGestureRecognizer(target: self, action: action)
    viewLIPIDES.addGestureRecognizer(tapLipides)
            
    let tapGlucides = UITapGestureRecognizer(target: self, action: action)
    viewGLUCIDES.addGestureRecognizer(tapGlucides)
    

    If we go a little further, we could put the view into an array and loop on them:

    let views = [viewCALORIES, viewPROTEINES, viewLIPIDES, viewGLUCIDES]
    let action = #selector(boingView(gesture:))
    
    views.forEach { aView in
        let tap = UITapGestureRecognizer(target: self, action: action)
        aView.addGestureRecognizer(tap)
    }