Как отслеживать множественные касания

Эй, у меня есть хороший кусок кода в моих штрихах, он был предоставлен мне @Sam_M.

Я пытаюсь в основном отслеживать местоположение нескольких пальцев при движении. Как будто Палец 1 здесь, а Палец 2 там. Так что на данный момент он будет печатать количество пальцев / касаний, которые в данный момент находятся в поле зрения и местоположении, но он не будет отслеживать оба отдельных пальца по отдельности. Я посмотрел вокруг только на 3 других вопроса, которые есть в stackoverflow. Но ни один из них не дал мне хорошего результата, который я могу реализовать быстро.

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

for touch: UITouch in event!.allTouches()! {

for (index,touch) in touches.enumerate() {
    let ptTouch = touch.locationInNode(self.view)
    print("Finger \(index+1): x=\(pTouch.x) , y=\(pTouch.y)")
 }
}

}

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {

for touch: UITouch in event!.allTouches()! {

for (index,touch) in touches.enumerate() {
    let ptTouch = touch.locationInNode(self.view)
    print("Finger \(index+1): x=\(pTouch.x) , y=\(pTouch.y)")
  }
 }
}

person Hunter    schedule 03.10.2016    source источник


Ответы (2)


Сенсорный объект для каждого пальца останется неизменным с тем же адресом памяти, пока он находится на экране. Вы можете отслеживать отдельные пальцы в сценарии с несколькими касаниями, сохраняя адреса сенсорных объектов в массиве, а затем сравнивая их с этим массивом, чтобы точно знать, какой палец движется.

var fingers = [String?](count:5, repeatedValue: nil)

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    super.touchesBegan(touches, withEvent: event)
    for touch in touches{
        let point = touch.locationInView(self.view)
        for (index,finger)  in fingers.enumerate() {
            if finger == nil {
                fingers[index] = String(format: "%p", touch)
                print("finger \(index+1): x=\(point.x) , y=\(point.y)")
                break
            }
        }            
    }        
}

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    super.touchesMoved(touches, withEvent: event)
    for touch in touches {
        let point = touch.locationInView(self.view)
        for (index,finger) in fingers.enumerate() {
            if let finger = finger where finger == String(format: "%p", touch) {
                print("finger \(index+1): x=\(point.x) , y=\(point.y)")
                break
            }
        }
    }
}

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    super.touchesEnded(touches, withEvent: event)
    for touch in touches {
        for (index,finger) in fingers.enumerate() {
            if let finger = finger where finger == String(format: "%p", touch) {
                fingers[index] = nil
                break
            }
        }
    }        
}

override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
    super.touchesCancelled(touches, withEvent: event)
    guard let touches = touches else {
        return
    }
    touchesEnded(touches, withEvent: event)
}

Обновлено для Swift 4

Кредит @Klowne

var fingers = [UITouch?](repeating: nil, count:5)

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesBegan(touches, with: event)
    for touch in touches{
        let point = touch.location(in: self.view)
        for (index,finger)  in fingers.enumerated() {
            if finger == nil {
                fingers[index] = touch
                print("finger \(index+1): x=\(point.x) , y=\(point.y)")
                break
            }
        }
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesMoved(touches, with: event)
    for touch in touches {
        let point = touch.location(in: self.view)
        for (index,finger) in fingers.enumerated() {
            if let finger = finger, finger == touch {
                print("finger \(index+1): x=\(point.x) , y=\(point.y)")
                break
            }
        }
    }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesEnded(touches, with: event)
    for touch in touches {
        for (index,finger) in fingers.enumerated() {
            if let finger = finger, finger == touch {
                fingers[index] = nil
                break
            }
        }
    }
}

override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesCancelled(touches, with: event)
    guard let touches = touches else {
        return
    }
    touchesEnded(touches, with: event)
}

* Согласно обновленной документации Apple, теперь можно сохранять касания во время последовательности мультитач, если они отпускаются в конце последовательности.

person Sam_M    schedule 03.10.2016
comment
Из документации: Никогда не удерживайте сенсорный объект при обработке события. Если вам нужно сохранить информацию о касании от одной фазы касания к другой, скопируйте эту информацию из касания - person matt; 03.10.2016
comment
Уууууууууууууууууууууу! Удивительно, это работает невероятно Идеально !!! У меня есть дополнительный вопрос. Я хочу прикрепить узел к пальцу № 2, как мне просто сказать node.position = finger2position, а также кто-то только что проголосовал против вашего вопроса, я не знаю, почему? но я проголосовал за то, чтобы вернуть его в норму @Sam_M - person Hunter; 03.10.2016
comment
Чтобы идентифицировать UITouch, не сохраняя его, нужно взять его адрес в памяти. Я добавил информацию в свой ответ, показывающую, как это сделать. - person matt; 03.10.2016
comment
@Hunter Я проголосовал за него, потому что он делает то, что, по словам Apple, вы не должны делать. Вы можете сохранить строковый идентификатор касания в массиве, но не само касание. - person matt; 03.10.2016
comment
о, хорошо, черт возьми. это работает невероятно, но если вы хотите играть по книге, то я понимаю, почему вы проголосовали против этого. Это все хороший человек. @матовый - person Hunter; 03.10.2016
comment
эй, Сэм, можешь обновить свой ответ этой строкой кода в ответе Мэтта? @Sam_M - person Hunter; 03.10.2016
comment
@matt Спасибо за ваш комментарий. Я обновил свой ответ, чтобы вместо этого использовать адреса памяти. - person Sam_M; 03.10.2016
comment
@Hunter Обновил ответ. - person Sam_M; 03.10.2016
comment
Это абсурд. Документы только говорят, что если вы сохраняете запись касания, вы должны отпустить ее, когда касание закончится. Вы можете и должны сохранить любой объект, который может понадобиться, при условии, что вы примете соответствующие меры для предотвращения утечки памяти. - person Luis Vieira Damiani; 04.01.2018
comment
@LuisVieiraDamiani Вы понимаете, что этому ответу и комментариям больше года, верно? В то время жирная часть первого комментария Мэтта была именно тем, что сказано в документации, с тех пор она должна была быть изменена. - person Sam_M; 05.01.2018
comment
Я понял это, когда писал, и до сих пор думаю, что идея неспособности хранить объект абсурдна. Возможно, Apple тоже это поняла и изменила документы? В любом случае ваш ответ работает отлично, и идея хранения строки, а не самого объекта несущественна, если вы установите ее на ноль, когда прикосновение закончится. Я разозлился, что люди заставили вас пройти через ненужные проблемы и даже проголосовали за вас из-за отсутствия критики в адрес самой Apple. Они тоже совершают ошибки. - person Luis Vieira Damiani; 05.01.2018
comment
хотя этот подход работает, он приносит дополнительную боль с утечками и пограничными случаями, когда touchesEnded или touchesCancelled не вызываются. или когда touchesBegan вызывается дважды. будь осторожен! - person ursa; 15.05.2020

Прикосновение — это палец. Палец — это прикосновение. Вы можете идентифицировать палец, идентифицируя прикосновение; касание определенного пальца будет идентично одному и тому же объекту, пока этот палец касается экрана. Чтобы получить уникальный идентификатор для конкретного UITouch, возьмите его адрес памяти, например:

let uuid = String(format: "%p", theTouch)

Вы можете сохранить уникальный идентификатор для каждого касания в свойстве. Но не сохраняйте само касание; Эппл запрещает.

person matt    schedule 03.10.2016
comment
Apple ничего не запрещает. У вас несколько эзотерическое отношение к этому делу. Документы говорят только о выпуске всего, что вы храните, поскольку новые объекты создаются каждый раз, когда начинается касание, чтобы не было утечки памяти. - person Luis Vieira Damiani; 04.01.2018
comment
Сенсорный объект сохраняется на протяжении всей последовательности мультитач. Вы можете сохранить ссылку на касание при обработке последовательности мультитач, если вы отпустите эту ссылку, когда последовательность закончится. Если вам нужно сохранить информацию о касании вне последовательности мультитач, скопируйте эту информацию из касания. - person Luis Vieira Damiani; 04.01.2018