I trying to use UIView
instead UIButton
as @duckSern1108 recommended.
I created a custom class for UIView
and created touch animation inside the class. Also in my main view controller I create UIView
class instance and add a UITapGestureRecouncer
for UIView
to repeat the button action behaviour. But after adding UITapGestureRecouncer
in main view controller the touchesEnded
function is not called inside the class. How to fix it?
class SLView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
animateScale(to: 0.9, duration: 0.4)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
animateScale(to: 1, duration: 0.38)
}
private func animateScale(to scale: CGFloat, duration: TimeInterval) {
UIView.animate(withDuration: duration,
delay: 0,
usingSpringWithDamping: 0.5,
initialSpringVelocity: 1.0,
options: [],
animations: {
self.transform = CGAffineTransform(scaleX: scale, y: scale)
}, completion: nil)
}
}
main vc
let settingsMenu = UIStackView()
var itemView = SLView()
func contextMenu() {
for index in 1...2 {
itemView = SLView()
itemView.tag = index
itemView.backgroundColor = .white.withAlphaComponent(0.75)
itemView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
itemView.layer.borderColor = UIColor.white.cgColor
itemView.layer.borderWidth = 4
itemView.layer.cornerRadius = 24
itemView.layoutMargins = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16)
itemView.translatesAutoresizingMaskIntoConstraints = false
settingsMenu.addArrangedSubview(itemView)
itemView.widthAnchor.constraint(equalToConstant: 232).isActive = true
itemView.heightAnchor.constraint(equalToConstant: 32).isActive = true
}
settingsMenuItemImage.widthAnchor.constraint(equalToConstant: 32).isActive = true
settingsMenuItemImage.heightAnchor.constraint(equalToConstant: 32).isActive = true
itemView.setCustomSpacing(16.0, after: itemView.subviews[0])
}
let contactGesture = UITapGestureRecognizer(target: self, action: #selector(self.contactWithDeveloper))
self.settingsMenu.subviews[0].addGestureRecognizer(contactGesture)
let restoreGesture = UITapGestureRecognizer(target: self, action: #selector(self.restorePurchase))
self.settingsMenu.subviews[1].addGestureRecognizer(restoreGesture)
}
@objc func another(_ sender: UITapGestureRecognizer) {
print("purchase")
}
@objc func restorePurchase(_ sender: UITapGestureRecognizer) {
print("purchase")
}
When you add a UITapGestureRecognizer
, when user lift finger, touchesEnded
is not forward from UITapGestureRecognizer
to your SLView
(as you see when testing), but touchesCancelled
is forwarded. So to animate, you should override touchesCancelled
.
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
animateScale(to: 1, duration: 0.38)
}
But here you don't need to combine UITapGestureRecognizer
with touchesBegan
and touchesEnded
just provide a closure for SLView
and call it when touchesEnded
:
var onTap: (() -> Void)?
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
animateScale(to: 1, duration: 0.38)
onTap?()
}