I made a toast view with a UIImageView
in it, what I want to do is everytime the user taps the image view, the toast dismisses itself. Naturally I configured a UITapGestureRecognizer
to my image view, but the selector function is not getting called. Here's what I did:
class ToastView: UIView {
private var icon: UIImageView!
init() {
super.init(frame: .zero)
setupViews()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupViews()
}
override func layoutSubviews() {
super.layoutSubviews()
setupConstraints()
}
private func setupViews() {
translatesAutoresizingMaskIntoConstraints = false
layer.cornerRadius = 8
isUserInteractionEnabled = true
icon = UIImageView()
icon.translatesAutoresizingMaskIntoConstraints = false
icon.image = UIImage(named: "someImage")
icon.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(iconHandler))
icon.addGestureRecognizer(tapGesture)
addSubview(icon)
}
private func setupConstraints() {
NSLayoutConstraint.activate([
topAnchor.constraint(equalTo: superview!.topAnchor, constant: 55),
leadingAnchor.constraint(equalTo: superview!.leadingAnchor, constant: 16),
trailingAnchor.constraint(equalTo: superview!.trailingAnchor, constant: -16),
icon.heightAnchor.constraint(equalToConstant: 16),
icon.widthAnchor.constraint(equalToConstant: 16),
icon.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
icon.centerYAnchor.constraint(equalTo: centerYAnchor),
])
}
@objc private func iconHandler(_ sender: UITapGestureRecognizer) {
// This function is not called
print("handle icon")
}
}
After some research, I tried to give the ToastView
a gesture recognizer instead of the image view. So I did give the tap gesture recognizer when showing the toast in my custom UIViewController
class like this:
class CustomViewController: UIViewController {
private var isShowingToast: Bool = false
private lazy var toast: ToastView = {
let toast = ToastView()
toast.isUserInteractionEnabled = true
toast.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(dismissToast)))
return toast
}()
func showToastWithMessage() {
if !isShowingToast {
view.addSubview(toast)
UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
self?.toast.alpha = 1
self?.toast.frame.origin.y += 10
self?.isShowingToast = true
}, completion: { _ in
UIView.animate(withDuration: 0.5, delay: 5.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
self?.toast.alpha = 0
self?.toast.frame.origin.y -= 10
}, completion: { [weak self] _ in
self?.isShowingToast = false
self?.toast.removeFromSuperview()
})
})
}
}
@objc private func dismissToast() {
// This functions does not get called as well
print("dismiss")
}
}
Unfortunately the dismiss function does not print to the console. Is there anyway to resolve this?
Looks like this occurs because of your animation. View is all the time in animation status and block tap gesture. U can try call it with delay instead of adding delay for your animation.
func showToastWithMessage() {
if !isShowingToast {
view.addSubview(toast)
UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
self?.toast.alpha = 1
self?.toast.frame.origin.y += 10
self?.isShowingToast = true
}, completion: { _ in
print("Completion")
})
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
self?.toast.alpha = 0
self?.toast.frame.origin.y -= 10
}, completion: { [weak self] _ in
self?.isShowingToast = false
self?.toast.removeFromSuperview()
})
}
}
}
This way view going to animate status after 5 sec not with 5 sec delay.
This is how your controller look like:
class CustomViewController: UIViewController {
private var isShowingToast: Bool = false
lazy var toast: ToastView = {
let toast = ToastView()
toast.isUserInteractionEnabled = true
toast.backgroundColor = .red
toast.translatesAutoresizingMaskIntoConstraints = false
toast.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(dismissToast)))
return toast
}()
override func viewDidLoad() {
super.viewDidLoad()
// Add Toast constraints
view.addSubview(toast)
toast.heightAnchor.constraint(equalToConstant: 200).isActive = true
toast.widthAnchor.constraint(equalTo: toast.heightAnchor).isActive = true
toast.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
toast.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
}
func showToastWithMessage() {
if !isShowingToast {
view.addSubview(toast)
UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
self?.toast.alpha = 1
self?.toast.frame.origin.y += 10
self?.isShowingToast = true
}, completion: { _ in
UIView.animate(withDuration: 0.5, delay: 5.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
self?.toast.alpha = 0
self?.toast.frame.origin.y -= 10
}, completion: { [weak self] _ in
self?.isShowingToast = false
self?.toast.removeFromSuperview()
})
})
}
}
@objc private func dismissToast() {
// This functions does not get called as well
print("dismiss")
}
}
And this is your class:
class ToastView: UIView {
private var icon = UIImageView()
init() {
super.init(frame: .zero)
setupViews()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupViews()
}
override func layoutSubviews() {
super.layoutSubviews()
setupConstraints()
}
private func setupViews() {
translatesAutoresizingMaskIntoConstraints = false
layer.cornerRadius = 8
isUserInteractionEnabled = true
icon.translatesAutoresizingMaskIntoConstraints = false
icon.image = UIImage(named: "profilo")?.withRenderingMode(.alwaysOriginal) //put your image here
icon.isUserInteractionEnabled = true
icon.layer.cornerRadius = 8
icon.layer.masksToBounds = true //set image masked round corner
icon.clipsToBounds = true
icon.contentMode = .scaleAspectFill //set image content mode
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(iconHandler))
icon.addGestureRecognizer(tapGesture)
}
private func setupConstraints() {
// Setup the constraints for the subviews
addSubview(icon)
icon.topAnchor.constraint(equalTo: topAnchor).isActive = true
icon.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
icon.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
icon.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
@objc private func iconHandler(_ sender: UITapGestureRecognizer) {
// This function is not called
print("handle icon")
}
}
this is the result:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.