Как отладить, кто ест мои прикосновения в UIKit?
Я не могу понять, почему нажатие на текстовые поля и кнопки в моем представлении не работает. Я проверил все очевидные вещи, как установлено ли userInteractionEnabled равным YES, независимо от того, установлен ли распознаватель жестов, и если на переднем плане есть невидимое представление.
Есть ли передовая практика в iOS для отслеживания касания, когда она впервые появляется там, где она потребляется?
UPDATE:
Оба ответа были полезны. В ходе моего расследования я узнал, что если subview находится за пределами своих родительских границ, даже если родительский объект не отсекает subviews, subview не будет получать события. Я распечатал цепочку наблюдений из текстового поля, которое не получало касаний, и я увидел, что один из этих представлений имел высоту 0. Я поставил некоторые ограничения, чтобы растянуть его, и моя проблема была решена.
Ответы
Ответ 1
Вы можете -[UIWindow sendEvent]:
подкласс UIWindow
и переопределить -[UIWindow sendEvent]:
затем, когда он вызывается, использовать -[UIWindow hitTest:withEvent:]
чтобы проверить, какое представление получит событие.
Затем вы можете вызвать -[UIView recursiveDescription]
чтобы напечатать некоторую отладочную информацию, которая поможет вам понять, почему это представление получило событие касания.
Не забудьте позвонить [super sendEvent:]
когда вы закончите.
Для тех, кто использует раскадровку и хочет знать, как мы можем изменить класс основного окна приложения:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow? = TestWindow()
// ....
}
Просто AppDelegate
значение по умолчанию для window
AppDelegate
var. Когда приложение запускается, UIApplicationMain
создает экземпляр делегата и запрашивает у него window
. Если window
равно nil
оно автоматически создаст новое. Но если мы предоставим здесь значение по умолчанию, оно будет использоваться во всем приложении.
Ответ 2
Не прямой ответ на вопрос, но очень распространенная причина исчезновения прикосновений заключается в том, что элемент управления находится в uiview, который имеет меньший размер, чем этот элемент управления, но не обрезает его границы, поэтому вы не увидите что родительский вид меньше (или даже возможно нулевого размера).
Parent UIView size=0x0, clipToBounds=false
Child UIButton size=100x50
= > Кнопка "Дети" не получит никаких событий касания.
Ответ 3
Вы можете использовать новую отладку в режиме реального времени Xcode6 и, повернув иерархию представлений в 3D, вы можете увидеть, какие виды находятся выше тех, которые вам нужны, и осмотреть их.
Ответ 4
Вы можете отладить это, используя символическую точку останова:
-[UIWindow sendEvent:]
& po $arg3
Журналы:
<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}
)}
Ответ 5
Мой полный Swift Пример, следующий за @Bryan Chen и @kelin Ответ...
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)
}
}
Ответ 6
Основной способ увидеть, что потребляет сенсорные события, - просто добавить представление отладки и переопределить метод hitTest(:event:)
. Прикрепите этот класс к любому представлению в раскадровке.
class DebugView: UIView {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let view = super.hitTest(point, with: event)
print("View")
print(view)
return view
}
}
Присоединение этого к корневому представлению контроллера даст вам доступ к представлению, которое потребляет событие касания. Обратите внимание, что метод hitTest будет вызываться дважды при каждом событии касания.