I can't figure out why tapping on text fields and buttons in my view is not working. I've checked all the obvious things like whether userInteractionEnabled is set to YES, whether a gesture recognizer is installed, and if there is an invisible view in the foreground.
Is there a best practice in iOS for tracing a touch from when it first appears to where it gets consumed?
UPDATE:
Both answers were helpful. During the course of my investigation I learned that if a subview is outside of its parent's bounds, even if the parent is not clipping subviews, the subview will not receive events. I printed out the chain of superviews from the text field that was not getting touches, and I saw that one of those views had a height of 0. I put in some constraints to stretch it out, and my problem was solved.
You can debug that by using a symbolic breakpoint:
-[UIWindow sendEvent:]
& po $arg3
Logs:
<UITouchesEvent: 0x6000026fa6d0> timestamp: 179462 touches: {(
<UITouch: 0x7f84d6f10380> phase: Began tap count: 1 force: 0.000
window: <UIWindow: 0x7f84d6d0ad10; frame = (0 0; 375 812); autoresize = W+H;
gestureRecognizers = <NSArray: 0x600001aa8870>; layer = <UIWindowLayer: 0x6000014bd7e0>> view: <UIView: 0x7f84d6d0bff0; frame = (0 0; 375 812);
autoresize = W+H; layer = <CALayer: 0x6000014bdc60>> location in window: {165.66665649414062, 232.33332824707031} previous location in window:
{165.66665649414062, 232.33332824707031} location in view: {165.66665649414062,
232.33332824707031} previous location in view: {165.66665649414062,232.33332824707031}
)}
You can subclass UIWindow
and override -[UIWindow sendEvent]:
, then when it is called, use -[UIWindow hitTest:withEvent:]
to test which view will receive the event.
You can then call -[UIView recursiveDescription]
to print some debug information help you understand why that view received the touch event.
Remember to call [super sendEvent:]
when you are done.
For those who use Storyboard and want to know how can we change the main application window class:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow? = TestWindow()
// ....
}
Just provide the default value for AppDelegate
's window
var. When the app is launched the UIApplicationMain
will instantiate a delegate and ask it for the window
. If the window
is nil
it will create a new one automatically. But if we provide a default value here, it will be used all over the app.
Not a direct answer to the question, but a very common cause of vanishing touches is for a control to be in a uiview which has a smaller size than that control, but is not clipping its bounds, so you won't see that the parent view is smaller (or even possibly zero-sized).
Parent UIView size=0x0, clipToBounds=false
Child UIButton size=100x50
=> Child Button won't get any touch events.
You can use the new Xcode6 live view debugging and by turning the view hierarchy in 3D you can see which views are above the ones you care for and inspect them.
My full Swift Example following @Bryan Chen and @kelin Answer ...
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow? = TestWindow()
// ....
}
...
class TestWindow:UIWindow {
override func sendEvent(_ event: UIEvent) {
print(event)
//<UITouchesEvent: 0x6000008b1f80> timestamp: 366545 touches: {(
// <UITouch: 0x7fa056d37dc0> phase: Ended tap count: 1 force: 0.000
//window: <zollundpost.TestWindow: 0x7fa056c020a0; baseClass = UIWindow;
//frame = (0 0; 375 812); gestureRecognizers = <NSArray: 0x6000034f9530>;
//layer = <UIWindowLayer: 0x600003abd940>> view: <UITableViewCellContentView:
//0x7fa059a55090; frame = (0 0; 375 72); opaque = NO; gestureRecognizers =
//<NSArray: 0x6000034293e0>; layer = <CALayer: 0x600003ac8320>> location in
//window: {165, 358.33332824707031} previous location in window:
//{144.33332824707031, 358.66665649414062} location in view: {165,
//44.999992370605469} previous location in view: {144.33332824707031,
//45.333320617675781}
// )}
super.sendEvent(event)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With