Подтвердить что ты не робот

Как отладить, кто ест мои прикосновения в UIKit?

Я не могу понять, почему нажатие на текстовые поля и кнопки в моем представлении не работает. Я проверил все очевидные вещи, как установлено ли userInteractionEnabled равным YES, независимо от того, установлен ли распознаватель жестов, и если на переднем плане есть невидимое представление.

Есть ли передовая практика в iOS для отслеживания касания, когда она впервые появляется там, где она потребляется?

UPDATE:

Оба ответа были полезны. В ходе моего расследования я узнал, что если subview находится за пределами своих родительских границ, даже если родительский объект не отсекает subviews, subview не будет получать события. Я распечатал цепочку наблюдений из текстового поля, которое не получало касаний, и я увидел, что один из этих представлений имел высоту 0. Я поставил некоторые ограничения, чтобы растянуть его, и моя проблема была решена.

4b9b3361

Ответ 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

enter image description here Журналы:

<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 будет вызываться дважды при каждом событии касания.