« Older: What 'AddArcToPoint' Does « Older
Newer: Code style guides »Newer »
iOS: What happens when I touch the screen?
When you touch the screen in iOS the first thing that needs to happen is to find the correct object to handle the tap or gesture. The way this is done is by calling
on the key window of the application (UIWindow is a subclass of UIView). This method will return the view that should handle gesture.
If you have set userInteractionEnabled
to NO
on this
view then hitTest:withEvent:
will always return nil
.
This will mean that neither the view nor any of its
subviews will respond to touches. If user interaction
is enabled then hitTest:withEvent:
will check to see if
it contains the point p
. If it doesn’t contain the point
p
then it will return NO
. This means means that none of
the view’s subviews will be tested to see if they contain the
point. This will cause a problem if you expect a view that
goes over the edge of its superview’s bounds to respond to
touches (it will only respond to touches that are also
inside the superview’s bounds).
If hitTest:withEvent:
determines that the point is within
the view’s bounds then it will start calling hitTest:withEvent:
on its subviews. If a subview returns a UIView
then this is
the UIView
that the current hitTest:withEvent:
will also return
(it won’t check the other subviews). This results in the UIView
that it returned being the one that handles the event. If none
of the subviews returns a UIView
then hitTest:withEvent:
returns
self
, and the current view will handle the event.
The order that hitTest:withEvent:
checks the subviews is
important, as if there are two subviews that might both
respond to a touch then only the first subview to have
hitTest:withEvent:
called on it will respond to that touch.
The order that the subviews are called is the reverse of the
order that you add them to the view i.e. the last subview
added to the view is the first subview that will have
hitTest:withEvent:
called on it.
So hitTest:WithEvent:
looks something like this:
This is useful stuff to know, as sometimes there may be a situation where something is not responding, and you’d like it to. For instance, if I have some views as in this image:
Here the button is a subview of the red view. In this case
if you clicked on the right hand side of the button (above the
white background) it wouldn’t respond. To solve this you can either
make it so pointInside:withEvent
(on the red view) returns YES
for the right-hand part of the button (if you do this the red view will
handle the touch if the button doesn’t). Or you can make it so
hitTest:withEvent:
(on the red view) returns the button when the
point is over the button, but not over the red view.
So you’d need to subclass the UIView
for the red view. If you override
the pointInside:withEven:
it might look something like this:
If instead you override the hitTest:withEvent:
method then
it may look something like this:
This will work well if the button is only over superviews. However
if the button is over a sibling view, or some other path in
the view hierarchy the other path in the view hierarchy may be hit
tested first and return a UIView
; so the button’s superview
doesn’t get hit tested, and the button won’t respond. In that
case you may need to either change the order of some subviews
(if you can), or override some other hit testing methods so the
siblings don’t respond for the points under the button.