The problem
- when
UIControl
Added to an object with a gestureUIView
And to giveUIControl
addedtarget-action
, then it will be executedUIControl
的target-action
orUIView
“?
I believe that this seems like an easy first question, at least 90% of iOSer will get it wrong.
Who responds to events
All subclasses that inherit from UIResponder
UIButton, UIView, UIWindow, UIApplication, etc…
What is an event
Touch, shake, etc
Graph TD finger touch screen --> IOKit. Framework encapsulates IOHIDEvent object --> forward to SprintBoard via MachPort --> forward to main thread of current APP via MachPort
RunLoop
- The main thread
RunLoop
的Source1
Trigger, triggerSource1
The callback:__IOHIDEventSystemClientQueueCallback()
Source1
The triggerSource0
The callback:__UIApplicationHandleEventQueue()
That will beIOHIDEvent
Encapsulated in theUIEvent
Source0
Is called internallyUIApplication
的sendEvent
将UIEvent
To pass toUIWindow
Determine who is the first responder
- Check whether hidden, transparent, interoperable, none
- Determines whether the click is in the view
- If in, to
FILO
To find whether the subview is in the click range - If not, check to see if it is in the peer view
The code is as follows:
override func hitTest(_ point: CGPoint.with event: UIEvent?). -> UIView? {
print(classTag, #function, self.point(inside: point, with: event))
if isHidden || !isUserInteractionEnabled || alpha < = 0.01 {
return nil
}
if self.point(inside: point, with: event) {
for subview in subviews.reversed() {
let convertedPoint = subview.convert(point, from: self)
let resultView = subview.hitTest(convertedPoint, with: event)
if let resultView = resultView {
return resultView
}
}
return self
}
return super.hitTest(point, with: event)
}
Copy the code
Passing events along the response chain
Identify the members of the response chain
First responder -> First Responder parent view -> Parent view of the parent view -> UIViewController -> UIWindow -> UIApplication
A nextResponder is a superView
A method for passing events
func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?).
func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?).
func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?).
func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?).
Copy the code
If the above method’s super is called, the event will still be passed, otherwise it will not be passed
When gesture recognition participates in the response chain
And the response chain
cancelsTouchesInView
The default is true. If set to false, touchesCancelled will not be sent to the target view. The result is that both the gesture and the method fire at the same time.
delaysTouchesBegan
The default is false. When set to true, a ‘touchesBegan’ is delayed until gesture recognition fails.
delaysTouchesEnded
The default is true. If set to false, touchesEnd will be triggered immediately; gestures like double clicking will not be triggered.
UIControl and gesture recognition
UIControl
usetarget-action
Respond to the event and no longer pass the event down the response chain.UIControl
的target-action
The trigger time was whentouchesEnd
After.- And this one above will cause, if there’s a gesture on the superview,
UIControl
Will not be able to executetarget-action
.So the answer above is to perform the superview gesture, notUIControl
的target-action
. - if
target-action
的target
为nil
, this will be changedaction
The extended response chain is passed down until it is discarded - if
target-action
的target
为self
Would go,runtime
Message forwarding, if none is eventually found, is reportedunrecgnize selector
The exception.
Reference:
IOS | events and response chain
IOS | response chain and gesture recognition