iOS touchesMoved перенаправляется только один раз с помощью UIButton

Моя цель, имея одновременно и то, и другое:

  • UIButton, обрабатывающий событие (.touchDown)
  • другое представление выше в иерархии (т. е. супер), которое получает touchBegan/Moved/Ended/Cancelled.

Я хочу это событие, потому что мне нужна сила касания и другие вещи для некоторых вычислений.


В верхнем/супер вид я переопределяю тач Начал и друзей, чтобы получить силы и прочее.

НО, по сути, UIButton не пересылает событие касания, поэтому (в этом примере) я расширяю UIButton (в моем коде я расширяю подкласс ~, но это не меняет проблему) и переопределяю touchesBegan и друзей и добавляю next?.touchesBegan(...) к нему.


Что работает:

  • touchesBegan(...) правильно перенаправляет в суперпредставление

Что не работает:

  • touchesMoved(...) только пересылать ОДИН РАЗ на свои super просмотров. (даже если кнопка touchesMoved называется, а next? не nil
  • touchesEnded(...) НЕ ВЫЗЫВАЕТСЯ, если touchesMoved(...) уже был вызван (только один вызов touchesMoved(...) если вы следуете). и снова next? не nil
// One of the overrided UIButton touches event
extension UIButton {
    open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("Button: touches began - ")
        super.touchesBegan(touches, with: event)
        next?.touchesBegan(touches, with: event)
        if next == nil { print("next was nil!") }
        print("Button: touches began - end\n")
    }
}

// One of the overrided ViewController touches event
// (which is only called once for touchesMoved, and then touchesEnded not called)
extension ViewController {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("ViewController: touches began - ")
        super.touchesBegan(touches, with: event)
        print("ViewController: touches began - end\n")
    }
}

Вот пример проекта, демонстрирующий проблему:


Если у кого-то есть какие-либо идеи о том, почему это ведет себя так, пожалуйста, дайте мне знать\o/


person itMaxence    schedule 19.11.2020    source источник


Ответы (1)


Я попробовал немного другой подход, используя подкласс UIGestureRecognizer. См. приведенный ниже код на основе вашего примерного проекта. Интересно, что UIButton проверяет состояние .begin, которое устанавливает touchesBegan. Возможно, вы сможете изменить свой код, чтобы не устанавливать состояние в методе touchesBegan. Посмотрите, работает ли это для вас.

Распознаватель жестов UIKit также предоставляет вам несколько методов делегирования и возможность использовать селектор, который имеет доступ к состоянию, установленному с помощью методов touches.... Но они не дают вам столько информации для каждого отдельного прикосновения.

Источники:

developer.apple.com/documentation/uikit/touche developer.apple.com/documentation/uikit/uigesturer

raywenderlich.com/6747815-uigesturerecognizer-tu

Код:

class ViewController: UIViewController {
    @IBOutlet weak var button: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        button.addTarget(self, action: #selector(buttonTouched), for: .touchDown)
        
        let gesture = CustomGesture()
        self.view.addGestureRecognizer(gesture)
        self.view.isUserInteractionEnabled = true
    }
    
    @objc
    func buttonTouched(button:UIButton) {
        print("Button ACTION!")
    }
}

class CustomGesture: UIGestureRecognizer {
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesBegan(touches, with: event)
        print("ViewController: touches began")
        //  state = .began //Do not set the state to .began as this seems to be blocking the UIButton gesture.
    }
    
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesMoved(touches, with: event!)
        for _ in touches {
            print("ViewController: touches moved")
        }
        state = .changed
    }
    
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesEnded(touches, with: event!)
        print("ViewController: touches ended")
        state = .ended
    }
    
    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesCancelled(touches, with: event!)
        print("ViewController: touches cancelled")
        state = .cancelled
    }
}
person Marco Boerner    schedule 19.11.2020