Reputation: 133
I'm trying to add a GestureRecognizer to a UIView which is an arranged subview of a UIStackView. I tried already this this or this. Also I tried to enable all underlying views for userInteraction, but it didn't work.
When I add the gesture recognizer to the imageView which is the parent view of the stackView, then the tap works. Strangely it also get's triggered when I tap on the "bannerView" which is a subview of the stackView and therefore lies on top of the imageView.
What's the proper way to get the tap gesture recognize on top of a stackViews's arrangedSubview?
Here my code:
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
var imageView: UIImageView!
var bannerStackView: UIStackView!
var bannerView: UIView!
override func loadView() {
let view = UIView()
view.backgroundColor = .white
self.view = view
setupImageView()
setupBannerStackView()
setupConstraints()
}
func setupImageView() {
let image = UIImage(named: "Apple.jpeg")
imageView = UIImageView(image: image)
imageView.backgroundColor = .red
view.addSubview(imageView)
}
func setupBannerStackView() {
bannerStackView = UIStackView()
bannerStackView.axis = .vertical
bannerStackView.alignment = .leading
bannerStackView.distribution = .equalCentering
bannerStackView.isUserInteractionEnabled = true
bannerView = UIView()
bannerView.backgroundColor = .blue
bannerStackView.addArrangedSubview(bannerView)
imageView.addSubview(bannerStackView)
/*
Also tried this but didn't work
*/
// let tapGesture = UITapGestureRecognizer(target: self, action:
#selector(onBannerTapped))
// bannerView.isUserInteractionEnabled = true
// bannerView.isUserInteractionEnabled = true
// bannerView.addGestureRecognizer(tapGesture)
for bannerView in bannerStackView.arrangedSubviews {
let tapGesture = UITapGestureRecognizer(target: self, action:
#selector(onBannerTapped))
bannerView.isUserInteractionEnabled = true
bannerView.addGestureRecognizer(tapGesture)
}
}
@objc func onBannerTapped() {
print("Banner view tapped!")
}
func setupConstraints() {
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 200).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 200).isActive = true
bannerStackView.translatesAutoresizingMaskIntoConstraints = false
bannerStackView.topAnchor.constraint(equalTo: imageView.topAnchor, constant: 10).isActive = true
bannerStackView.leadingAnchor.constraint(equalTo: imageView.leadingAnchor).isActive = true
bannerView.translatesAutoresizingMaskIntoConstraints = false
bannerView.heightAnchor.constraint(equalToConstant: 30).isActive = true
bannerView.widthAnchor.constraint(equalToConstant: 80).isActive = true
}
}
Upvotes: 0
Views: 2415
Reputation: 77690
.isUserInteractionEnabled
cascades to subviews. So, even if I set it to true on a subview, if the subview's superview (or its superview, and on up the hierarchy) has .isUserInteractionEnabled
set to false
, the subview will not get touch events.
So, the first thing to do is check .isUserInteractionEnabled
on each view in the hierarchy.
In your func, remove this line:
bannerStackView.isUserInteractionEnabled = true
then add these lines after creating your tapGesture
:
print("imageView isUserInteractionEnabled:", imageView.isUserInteractionEnabled)
print("bannerStackView isUserInteractionEnabled:", bannerStackView.isUserInteractionEnabled)
print("bannerView isUserInteractionEnabled:", bannerView.isUserInteractionEnabled)
So it looks like this:
func setupBannerStackView() {
bannerStackView = UIStackView()
bannerStackView.axis = .vertical
bannerStackView.alignment = .leading
bannerStackView.distribution = .equalCentering
// remove this line (comment-it out)
// bannerStackView.isUserInteractionEnabled = true
bannerView = UIView()
bannerView.backgroundColor = .blue
bannerStackView.addArrangedSubview(bannerView)
imageView.addSubview(bannerStackView)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onBannerTapped))
bannerView.addGestureRecognizer(tapGesture)
print("view isUserInteractionEnabled:", view.isUserInteractionEnabled)
print("imageView isUserInteractionEnabled:", imageView.isUserInteractionEnabled)
print("bannerStackView isUserInteractionEnabled:", bannerStackView.isUserInteractionEnabled)
print("bannerView isUserInteractionEnabled:", bannerView.isUserInteractionEnabled)
}
You should see this output:
view isUserInteractionEnabled: true
imageView isUserInteractionEnabled: false
bannerStackView isUserInteractionEnabled: true
bannerView isUserInteractionEnabled: true
and that tells you.... you simply need to add:
imageView.isUserInteractionEnabled = true
Upvotes: 3