I am creating a reusable MetaControl
that consists of a few sub-controls (see pic). It inherits from UIControl
, and contains 2 simple UIButtons
and a custom slider I created. The CustomSlider
also inherits from UIControl
.
In the MetaControl
's initializer, I add some target actions that receive events from the sub-controls to inform the MetaControl
of changes.
class MetaControl: UIControl {
public override init(frame: CGRect) {
self.slider.addTarget(self, action: #selector(sliderValueChanged), for: .valueChanged)
self.slider.addTarget(self, action: #selector(sliderTouched), for: .touchDown)
self.button1.addTarget(self, action: #selector(button1Pressed), for: .touchDown)
self.button2.addTarget(self, action: #selector(button2Pressed), for: .touchDown)
}
}
and then later I put the selector:
@objc private func sliderTouched() {
print("The slider was touched")
}
The problem I'm having is with the sliderTouched()
event. This event gets fired twice whenever I touch the slider.
MetaControl
itself.CustomSlider
itself.My question is, how can I prevent the MetaControl
itself from responding to events, while still allowing my CustomSlider
to send its actions?
I used 2 ways to confirm that it was the MetaControl
itself which triggered the extra event:
Commented out the action sending code in the CustomSlider
. Even without this line of code, sliderTouched()
is still called:
class CustomSlider: UIControl {
var isTouched = false {
didSet {
//sendActions(for: .touchDown)
}
}
}
Replaced the .touchDown
action with .applicationReserved
. Since I'm no longer using .touchDown
, the MetaControl
's .touchDown
event is never called.
class CustomSlider: UIControl {
var isTouched = false {
didSet {
sendActions(for: .applicationReserved)
}
}
}
Interestingly, the UIButtons
do not cause this same problem. Pressing the UIButton
does not cause two events to be fired. How can I achieve this same thing?
P.S. The way I am causing the events to be sent from the CustomSlider
is through a custom UIPanGestureRecognizer
which is embedded into the CustomSlider
's own initializer.
I used this as a guideline: https://www.raywenderlich.com/82058/custom-control-tutorial-ios-swift-reusable-knob
P.P.S I hope I'm not going about this the wrong way-- embedding all these sub-controls into a MetaControl
that then itself inherits from UIControl
. The MetaControl
itself never responds to touch events-- only the subcontrols. I'm using the MetaControl
mostly as a container to manage the shared state, provide structure to the layout, and to make the control re-usable. Eventually, I need many of them.
The answer was to make sure to also override touchesBegan
in the slider.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
}