UIButton不响应使用UIScrollView触摸的ViewController

UIButtons do not respond to touched on ViewController with UIScrollView

提问人:Vladimir Kovalev 提问时间:11/6/2023 最后编辑:HangarRashVladimir Kovalev 更新时间:11/10/2023 访问量:29

问:

我正在开发嵌入了UIScrollView的ViewController。我有:view -> scrollView -> contentView (UIView) -> backgroundImageView -> SettingsItemsView (UIView) -> UIButtons。因此,在 SettingsItemsView 内的 UIButtons 上添加目标后,它们都不会响应触摸。由于UIScrollView,很可能存在冲突,但我没有设法解决它。提前致谢!代码已附上

控制器

final class SettingsViewController: ViewController {
    
    var viewModel: SettingsViewModel!
    
    private let scrollView: UIScrollView = {
        let sv = UIScrollView()
        sv.alwaysBounceVertical = true
        sv.delaysContentTouches = false
        return sv
    }()
    
    private let contentView: UIView = {
        let view = UIView()
        return view
    }()
    
    private let backgroundImageView: UIImageView = {
        let iv = UIImageView()
        iv.image = Asset.Images.settingsBackground.image
        iv.contentMode = .scaleToFill
        iv.isUserInteractionEnabled = true
        iv.clipsToBounds = true
        return iv
    }()
    
    private let settingsItemsView: SettingsItemsView = {
        let view = SettingsItemsView()
        return view
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        let titleLabel = UILabel()
        titleLabel.text = "Settings"
        if let font = FontFamily.JosefinSans.semiBold.font(size: 24) {
            titleLabel.font = font
        }
        titleLabel.textColor = Asset.Colors.white.color
        navigationItem.titleView = titleLabel
    }
    
    override func arrangeSubviews() {
        super.arrangeSubviews()
        view.addSubview(backgroundImageView)
        backgroundImageView.addSubview(scrollView)
        scrollView.addSubview(contentView)
        contentView.addSubview(settingsItemsView)
    }
    
    override func setupViewConstraints() {
        super.setupViewConstraints()
        
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        contentView.translatesAutoresizingMaskIntoConstraints = false
        backgroundImageView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            scrollView.topAnchor.constraint(equalTo: view.topAnchor),
            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            
            contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
            contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
            contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
            contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
            contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
            
            backgroundImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            backgroundImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            backgroundImageView.topAnchor.constraint(equalTo: view.topAnchor),
            backgroundImageView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])

        settingsItemsView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            settingsItemsView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
            settingsItemsView.widthAnchor.constraint(equalToConstant: 343),
            settingsItemsView.heightAnchor.constraint(equalToConstant: 350),
            settingsItemsView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 40)
        ])
    }
}

设置查看

final class SettingsItemsView: UIView {
    // Temporary image
    private var tempImage = UIImage(systemName: "apple.logo")

    private lazy var items: [SettingsItem] = [
        SettingsItem(option: SettingsOptions.privacy),
        SettingsItem(option: SettingsOptions.termsOfUse),
        SettingsItem(option: SettingsOptions.feedback),
        SettingsItem(option: SettingsOptions.share),
        SettingsItem(option: SettingsOptions.rate),
    ]

    private func configureOptions() -> [SettingsItemButton] {
        var options: [SettingsItemButton] = []

        for item in items {
            let button = SettingsItemButton(image: item.option.image!, name: item.option.name, option: item.option)
            button.clipsToBounds = true
            button.backgroundColor = .clear
            button.addTarget(self, action: #selector(testTapped(_:)), for: .touchUpInside)
            button.isUserInteractionEnabled = true
            options.append(button)
        }
        return options
    }

    @objc func testTapped(_ sender: SettingsItemButton) {
        print("Tapped: \(sender)")
    }

    private let stackView: UIStackView = {
        let stack = UIStackView()
        stack.axis = .vertical
        stack.distribution = .equalCentering
        stack.spacing = 0
        return stack
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }

    private func setupView() {
        addSubview(stackView)
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.topAnchor.constraint(equalTo: topAnchor).isActive = true
        stackView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        stackView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        stackView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        setupStyle()
        addSubviews()
    }

    private func addSubviews() {
        configureOptions().forEach { stackView.addArrangedSubview($0) }
    }

    private func setupStyle() {
        backgroundColor = Asset.Colors.tabBarBackground.color
        layer.cornerRadius = 22
        clipsToBounds = true
    }
}

按钮

final class SettingsItemButton: UIButton {
    
    var option: SettingsOptions!

    private let itemImage: UIImageView = {
        let btn = UIImageView()
        btn.tintColor = Asset.Colors.white.color
        btn.contentMode = .scaleAspectFill
        btn.backgroundColor = .blue
        return btn
    }()
    
    private let itemCheckMark: UIImageView = {
        let btn = UIImageView()
        btn.image = Asset.Images.arrowRight.image
        btn.tintColor = Asset.Colors.white.color
        btn.backgroundColor = .blue
        return btn
    }()
    
    private let itemName: UILabel = {
        let label = UILabel()
        if let customFont = FontFamily.Outfit.medium.font(size: 17) {
            label.font = customFont
        }
        label.textColor = Asset.Colors.white.color
        label.backgroundColor = .blue
        return label
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupSubviews()
        setupConstraints()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    convenience init(image: UIImage, name: String, option: SettingsOptions) {
        self.init(frame: .zero)
        configure(image: image, name: name, option: option)
    }
    
    func configure(image: UIImage, name: String, option: SettingsOptions) {
        self.option = option
        itemImage.image = image
        itemName.text = name
    }
    
    func setupConstraints() {
        itemImage.translatesAutoresizingMaskIntoConstraints = false
        itemName.translatesAutoresizingMaskIntoConstraints = false
        itemCheckMark.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            itemImage.centerYAnchor.constraint(equalTo: centerYAnchor),
            itemImage.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 24),
            itemImage.heightAnchor.constraint(equalToConstant: 24),
            itemImage.widthAnchor.constraint(equalToConstant: 24),
            
            itemName.centerYAnchor.constraint(equalTo: centerYAnchor),
            itemName.leadingAnchor.constraint(equalTo: itemImage.trailingAnchor, constant: 16),
            
            itemCheckMark.centerYAnchor.constraint(equalTo: centerYAnchor),
            itemCheckMark.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
            itemCheckMark.heightAnchor.constraint(equalToConstant: 32),
            itemCheckMark.widthAnchor.constraint(equalToConstant: 24)
        ])
    }
    
    func setupSubviews() {
        addSubview(itemImage)
        addSubview(itemName)
        addSubview(itemCheckMark)
    }
}

我尝试使用 UICollectionView 而不是 UIStackView。但是单元格上没有按钮,单元本身也对触摸没有反应。我还尝试将不同层上的isUserInteractionEnabled属性设置为false,以防止一些冲突。

iOS Swift 自动布局

评论

1赞 DonMag 11/7/2023
我们无法评估您发布的代码,因为它依赖于太多您未提供的内容 - 例如......func 覆盖,不覆盖任何内容......从简单开始 -- 一次实现一个元素,直到你发现什么不起作用。两个可能的问题:您已将按钮添加到视图中,但尚未确保按钮完全在该视图的边界内,或者您添加了覆盖/重叠按钮的视图。SettingsViewModelSettingsItemSettingsItem

答:

0赞 DonMag 11/10/2023 #1

在挖掘您的代码并进行一些编辑以使其运行之后......

您的按钮不会响应点击,因为包含它们的堆栈视图超出了其超级视图的边界。

在你的,你没有身高。如果设置:SettingsViewControllercontentView.clipsToBounds = true

private let contentView: UIView = {
    let view = UIView()
    // set clips to bounds true
    view.clipsToBounds = true
    return view
}()

并运行该应用程序,您甚至不会再看到按钮。

如果添加此行:

    NSLayoutConstraint.activate([
        settingsItemsView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
        settingsItemsView.widthAnchor.constraint(equalToConstant: 343),
        settingsItemsView.heightAnchor.constraint(equalToConstant: 350),
        settingsItemsView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 40),
        
        // add this line
        settingsItemsView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20.0),
        
    ])

你现在将有一个高度......你会再次看到按钮......您现在可以点击它们。contentView