how to factorize a function including a selector? - swift

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

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)
}

Related

Tableview menu not scrolling till the bottom swift

I have a slight problem, my menu which I created doesn't seem to want to scroll till the bottom.
I have created it programmaitacally
var dataSource = [String]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.register(CellClass.self, forCellReuseIdentifier: "Cell")
}
func addTransparentView(frames: CGRect) {
let window = UIApplication.shared.keyWindow
transparentView.frame = window?.frame ?? self.view.frame
self.view.addSubview(transparentView)
tableView.frame = CGRect(x: frames.origin.x, y: frames.origin.y + frames.height, width: frames.width, height: 50)
self.view.addSubview(tableView)
tableView.layer.cornerRadius = 4
transparentView.backgroundColor = UIColor.black.withAlphaComponent(0.9)
tableView.reloadData()
let tapgesture = UITapGestureRecognizer(target: self, action: #selector(removeTransparentView))
transparentView.addGestureRecognizer(tapgesture)
transparentView.alpha = 0
UIView.animate(withDuration: 0.4, delay: 0.0, usingSpringWithDamping: 2.0, initialSpringVelocity: 2.0, options: .curveEaseInOut,animations: {
self.transparentView.alpha = 0.5
self.tableView.frame = CGRect(x: frames.origin.x, y: frames.origin.y + frames.height + 1, width: frames.width, height: CGFloat(self.dataSource.count * 50))
}, completion: nil)
}
#objc func removeTransparentView() {
let frames = selectedButton.frame
UIView.animate(withDuration: 0.4, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut,animations: {
self.transparentView.alpha = 0
self.tableView.frame = CGRect(x: frames.origin.x, y: frames.origin.y + frames.height, width: frames.width, height: 0)
}, completion: nil)
}
#IBAction func onClickSelectProperty(_ sender: Any) {
dataSource = ["Apartment A3","Apartment A4","Apartment A5","Apartment A6","Apartment A8","Apartment A9","Apartment A12","Apartment E1","Sectional Title 50A","Sectional Title 65A","Free Standing 70A","Free Standing 70A Core","Free Standing 85A","Free Standing 100A"]
selectedButton = btnSelectPropert
addTransparentView(frames: btnSelectPropert.frame)
}
I would like to scroll till the bottom, somehow it doesn't allow me
how the table/menu looks like

Constraint animation doesnt animate y position change

This code is to expand a label by disabling the constraint which is keeping it at a max height of 54 to a full size. It works as it should but it jumps to the new y position straight away (without animating) and changes frame height after which makes it look like it jumps before animating
#IBOutlet var descriptionHeightConstraint: NSLayoutConstraint!
#IBAction func toggleFullDescription(_ sender: Any) {
if descriptionHeightConstraint.isActive {
self.layoutIfNeeded()
descriptionHeightConstraint.isActive = false
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut, animations: {
self.layoutIfNeeded()
}, completion: nil)
//seeMoreButton.setTitle("See less", for: .normal)
} else {
self.layoutIfNeeded()
descriptionHeightConstraint.isActive = true
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut, animations: {
self.layoutIfNeeded()
}, completion: nil)
//seeMoreButton.setTitle("See more", for: .normal)
}
}
Video of the issue

Using Xcode 11.4.1, Why do these errors show in the animation part?

Why am I getting these errors when I try to call the animation function, handleTapAnimation(), inside of viewDidLoad()? I provided a relevant screenshot below the code snippet.
For reference, I am using Xcode 11.4.1 as my IDE.
import UIKit
class ViewController: UIViewController {
// Other methods
override func viewDidLoad() {
super.viewDidLoad()
setupLabel()
setupStackView()
//animation
view.addGestureRecognizer(UITapGestureRecognizer(target: self,
action: #selector(handleTapAinmation)))
}
#objc fileprivate func handleTapAnimation() {
print ("Animating")
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseOut, animations: {
self.titleLabel.transform = CGAffineTransform(translationX: -30, y: 0)
}) { (_) in
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.titleLabel.alpha = 0
self.titleLabel.transform =
self.titleLabel.transform.translatedBy(x: 0,y: -200)
})
}
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseOut, animations: {
self.titleLabel.transform = CGAffineTransform(translationX: -30, y: 0)
}) { (_) in
UIView.animate(withDuration: 0.5, delay: 0.5, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.bodyLabel.alpha = 0
self.bodyLabel.transform =
self.bodyLabel.transform.translatedBy(x: 0,y: -200)
})
}
}
Any help is much appreciated.
just copy the line 46 and paste it into viewdidload()
and put the handleTapAnimation() func to the viewcontroller class because you wrote it outside the viewcontroller as iguess

How to repeat flip animation?

I'm trying to create my own activity indicator view like twitch chat activity indicator view. But I've tried to use animate .repeat:
override func animate() {
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [.repeat, .transitionFlipFromLeft], animations: {
self.flip()
}, completion: nil)
}
and also timer
let timer = Timer.init(timeInterval: 2, target: self, selector: #selector(flip), userInfo: nil, repeats: true)
Here is my flip() function
func flip() {
self.isFlipped = !self.isFlipped
let fromView = self.isFlipped ? self.view1 : self.view2
let toView = self.isFlipped ? self.view2 : self.view1
UIView.transition(from: fromView, to: toView, duration: 1, options: [.transitionFlipFromTop, .showHideTransitionViews], completion: nil)
}
But it did not work. I don't know what I missed. Can you guys help me please?

How to fix `prepareForSegue()` override `UIViewAnimation`

I have MainViewController which has stack view and its width is over screen's width. There is slide out menu at left side of storyboard. And there is Menu button on the screen which triggers an animation to changes UIStackView's from -260 to 0. But when I click some button at slide out menu, prepareForSegue() overrides the animation and content changes immediately. How can fix that?
You can find a gif below.
Here is the codes:
class MainViewController: UIViewController
{
var container: ContainerViewController?
#IBOutlet weak var superView: UIStackView!
#IBAction func menuButtonsChangeContent(sender: AnyObject) {
switch(sender.tag){
case 1:
container?.changeContent("first")
case 2:
container?.changeContent("second")
case 3:
container?.changeContent("third")
default:
break
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Container"{
self.slideOutMenu("")
container = segue.destinationViewController as? ContainerViewController
}
}
#IBAction func slideOutMenu(sender: AnyObject) {
if self.superView.frame.origin.x != -260 {
UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: .CurveEaseInOut, animations: ({
self.superView.frame = CGRect(x: -260, y: 20, width: self.superView.frame.width, height: self.superView.frame.height)
}), completion: nil)
}else{
UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: .CurveEaseInOut, animations: ({
self.superView.frame = CGRect(x: 0, y: 20, width: self.superView.frame.width, height: self.superView.frame.height)
}), completion: nil)
}
}
}
//ContainerViewController.swift
class ContainerViewController: UIViewController
{
var sourceVC: UIViewController?
var destinationVC: UIViewController?
var segueIdentifier: String?
var counter = 0
func changeContent(segueIdentifier: String)
{
self.performSegueWithIdentifier(segueIdentifier, sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: .CurveEaseInOut, animations: ({
if self.sourceVC != nil {
self.sourceVC?.view.removeFromSuperview()
print("deleted")
}
self.destinationVC = segue.destinationViewController
self.addChildViewController(self.destinationVC!)
self.destinationVC?.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
self.view.addSubview((self.destinationVC?.view)!)
self.destinationVC?.didMoveToParentViewController(self)
self.sourceVC = self.destinationVC
}), completion: nil)
}
}
And Storyboard:
GIF:
I was using a UIStackView as super view in MainViewController but an issue about shadows came up and I changed UIStackView to UIView. Maybe it is weird but the problem is gone.