Swift 将 GestureRecognizer 添加到 UIStackView 之上的视图

Swift add GestureRecognizer to View on top of UIStackView

我正在尝试将 GestureRecognizer 添加到 UIView,它是 UIStackView 的排列子视图。我已经试过了 this or this。我还尝试为 userInteraction 启用所有基础视图,但它没有用。

当我将手势识别器添加到作为 stackView 的父视图的 imageView 时,点击就起作用了。奇怪的是,当我点击 "bannerView" 时它也会被触发,它是 stackView 的子视图,因此位于 imageView 的顶部。

在 stackViews 的 arrangedSubview 上识别点击手势的正确方法是什么?

这是我的代码:

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

.isUserInteractionEnabled 级联到子视图。因此,即使我在子视图上将其设置为 true,如果子视图的父视图(或其父视图,以及在层次结构中)将 .isUserInteractionEnabled 设置为 false,子视图将不会获得触摸事件。

因此,首先要做的是检查 .isUserInteractionEnabled 层次结构中的每个视图。

在你的函数中,删除这一行:

    bannerStackView.isUserInteractionEnabled = true

然后在创建 tapGesture 后添加这些行:

    print("imageView isUserInteractionEnabled:", imageView.isUserInteractionEnabled)
    print("bannerStackView isUserInteractionEnabled:", bannerStackView.isUserInteractionEnabled)
    print("bannerView isUserInteractionEnabled:", bannerView.isUserInteractionEnabled)

所以看起来像这样:

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)

}

你应该看到这个输出:

view isUserInteractionEnabled: true
imageView isUserInteractionEnabled: false
bannerStackView isUserInteractionEnabled: true
bannerView isUserInteractionEnabled: true

这告诉你....你只需要添加:

imageView.isUserInteractionEnabled = true