简体   繁体   中英

Swift: UIScrollView & UIControl - addTarget | addGestureRecognizer - Not working as expected

I am working with UIScrollView and UIStackView to scroll horizontally and select a UIControl element.

I have addTarget set on a UIControl element as follows inside a UIStackView :
ie HighlightColorView is of type UIControl

lazy var colorsStackView: UIStackView = {
        let stackView = UIStackView()
        stackView.axis = .horizontal
        stackView.distribution = .fillEqually
        stackView.isUserInteractionEnabled = true
        stackView.alignment = .center
        stackView.spacing = 12
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.isUserInteractionEnabled = true
        for color in colors {
            let colorView = HighlightColorView()
            colorView.backgroundColor = color
            colorView.addTarget(self, action: #selector(self.handleColorTap(_:)), for: .touchUpInside)
            stackView.addArrangedSubview(colorView)
        }
        return stackView
    }()

@objc func handleColorTap(_ sender: UIView) {
        highlightSelectionDelegate.didTapColor(colorView: sender, mainView: self)
        let viewBackgroundColor = sender.backgroundColor ?? .black
        print("🎯", viewBackgroundColor)
    }

The issue is that when you tap on a colorView which is of type UIControl the tap doesn't work as expected. There seems to be a freeze and it only works when the view is dismissed.
Basically you tap on a color and nothing happens then when you dismiss the view then the tap registers and starts working. It seems to be an issue with the scrollView but I am not sure.

Implementation of the scrollView :

lazy var scrollView: UIScrollView = {
        let scView = UIScrollView()
        scView.contentInset = UIEdgeInsets(top: 0, left: 12, bottom: 0, right: 12)
        scView.showsHorizontalScrollIndicator = false
        scView.translatesAutoresizingMaskIntoConstraints = false
        scView.isUserInteractionEnabled = true
        scView.delaysContentTouches = false
        return scView
    }()

The use case it to be able to scroll on colors and tap them to highlight a text.

One thing I noticed is that you may be referring to UITapGestureRecognizer . if you are using UIGestureRecognizer by itself then it won't work.

     let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleColorTap))
     view.addGestureRecognizer(tapRecognizer)

To answer the question you asked

A UIGestureRecognizer is to be used with a single view. answer by @TomSwift.
I think this applies in your case where you are using multiple views. set addTarget or addGestureRecognizer to only one view.

If you are using multiple view such as in your case where you have a UIControl inside a UIStackView and the UIStackView inside a UIScrollView you need to make sure that addTarget or addGestureRecognizer is only set to one of the views only.

Since you want the UIControl to respond to a tap you need to set addTarget only on this view and not on the UIScrollView and/or UIStackView .

for color in colors {
    let colorView = HighlightColorView()
    colorView.backgroundColor = color
    colorView.addTarget(self, action: #selector(handleColorTap(_:)), for: .touchUpInside)
    colorsStackView.addArrangedSubview(colorView)
  }

Note: You do not have to put the code inside a viewDidLoad function, It is fine where it is. Just remove additional addTarget or addGestureRecognizer from your views.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM