Swift 将 GestureRecognizer 添加到 UIStackView 之上的 View

Posted

技术标签:

【中文标题】Swift 将 GestureRecognizer 添加到 UIStackView 之上的 View【英文标题】:Swift add GestureRecognizer to View on top of UIStackView 【发布时间】:2020-02-02 17:04:38 【问题描述】:

我正在尝试将 GestureRecognizer 添加到 UIView,它是 UIStackView 的排列子视图。我已经试过这个this 或this。我还尝试为 userInteraction 启用所有底层视图,但没有成功。

当我将手势识别器添加到作为 stackView 的父视图的 imageView 时,点击会起作用。奇怪的是,当我点击作为 stackView 的子视图的“bannerView”时,它也会被触发,因此位于 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


【问题讨论】:

我认为这行不通。因为有像“Z-stack”这样的东西,这意味着你只需要点击视图的顶部。所以你只能在视图顶部添加手势 查看我的代码,这正是我正在做的:将 GestureRecognizer 添加到最顶层视图的“bannerView”中。 (只是我没有使用具有 Z-Stack 的 SwiftUI 实现)。任何其他想法可能有什么问题? 【参考方案1】:

.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

【讨论】:

以上是关于Swift 将 GestureRecognizer 添加到 UIStackView 之上的 View的主要内容,如果未能解决你的问题,请参考以下文章

单元格中的 swift GestureRecognizer

在swift中使用类类型变量作为函数参数[重复]

是否可以将 GestureRecognizer 添加到自定义 UIView 子视图中的标签

从 Interface Builder 连接时,GestureRecognizer 操作未触发

使用点击手势识别器时,IOS swift应用程序无法正常工作

使用 UIPanGestureRecognizer 获取视图的翻译 - 快速 - 以编程方式