#ios #swift #uigesturerecognizer
#iOS #swift #пользовательский распознаватель
Вопрос:
Я новичок в разработке iOS. В настоящее время мне нужно разработать ForceTouchGestureRecognizer с 2-секундной активацией при запуске пользователем touch
Но состояние для жеста принудительного касания очень хорошо передается после добавления holdFor > minimumPressDuration
Кажется, что .changed
состояние не может быть достигнуто
Есть вывод на консоль
Ниже приведен код для класса ForceTouchGestureRecognizer
import UIKit
import UIKit.UIGestureRecognizerSubclass
class ForceTouchGestureRecognizer: UIGestureRecognizer {
var minimumValue: CGFloat = 0 // Value between 0.0 - 1.0 that needs to be reached before gesture begins
var tolerance: CGFloat = 1 // Once force drops below maxValue - tolerance, the gesture ends
var minimumPressDuration: Int = 1000
private(set) var forceValue: CGFloat? // value between 0.0 - 1.0
private var maxValue: CGFloat = 0
private var touchStartTime: Int = 0
override func reset() {
super.reset()
forceValue = nil
maxValue = 0
minimumPressDuration = 1500
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesBegan(touches, with: event)
if #available(iOS 9.0, *) {
if touches.count != 1 {
state = .failed
}
touchStartTime = Int(NSDate().timeIntervalSince1970 * 1000)
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesMoved(touches, with: event)
if #available(iOS 9.0, *) {
let touch = touches.first!
let value = touch.force / touch.maximumPossibleForce
let holdFor = Int(NSDate().timeIntervalSince1970 * 1000) - touchStartTime
if state == .possible {
if value > minimumValue amp;amp; holdFor > minimumPressDuration {
self.state = .began
}
} else {
if value < (maxValue - tolerance) {
state = .ended
} else {
maxValue = max(self.forceValue ?? 0, maxValue)
self.forceValue = value
state = .changed
}
}
}
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesCancelled(touches, with: event)
if state == .began || state == .changed {
state = .cancelled
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesEnded(touches, with: event)
if state == .began || state == .changed {
state = .ended
}
}
}
Обновлено 17 марта 2019
Согласно ответу Craz1k0ek. Я думаю, будет неплохо опубликовать мой обработанный код здесь
import UIKit.UIGestureRecognizerSubclass
class ForceTouchGestureRecognizer: UIGestureRecognizer {
var minimumValue: CGFloat = 0 // Value between 0.0 - 1.0 that needs to be reached before gesture begins
var tolerance: CGFloat = 1 // Once force drops below maxValue - tolerance, the gesture ends
var minimumPressDuration: TimeInterval = 1.5
private(set) var forceValue: CGFloat? // value between 0.0 - 1.0
private var maxValue: CGFloat = 0
private var touchStartTime: TimeInterval?
override func reset() {
super.reset()
forceValue = nil
maxValue = 0
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesBegan(touches, with: event)
if #available(iOS 9.0, *) {
if touches.count != 1 {
state = .failed
}
touchStartTime = Date().timeIntervalSince1970
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
guard touchStartTime != nil else { return }
super.touchesMoved(touches, with: event)
if #available(iOS 9.0, *) {
let touch = touches.first!
let value = touch.force / touch.maximumPossibleForce
let holdFor = NSDate().timeIntervalSince1970 - touchStartTime!
if holdFor > minimumPressDuration {
if state == .possible {
if value > minimumValue {
self.state = .began
}
} else {
if value < (maxValue - tolerance) {
state = .ended
} else {
maxValue = max(self.forceValue ?? 0, maxValue)
self.forceValue = value
state = .changed
}
}
}
}
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesCancelled(touches, with: event)
if state == .began || state == .changed {
state = .cancelled
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesEnded(touches, with: event)
if state == .began || state == .changed {
state = .ended
}
}
}
Ответ №1:
Я действительно хочу процитировать документацию:
Особые соображения Подклассы UIGestureRecognizer должны использовать версию свойства state для чтения и записи. Они получают это повторное объявление при импорте заголовочного файла UIGestureRecognizerSubclass.h…
Я упростил ваш распознаватель жестов, чтобы он активировался через две секунды. Обратите внимание, что я вижу некоторую несогласованность в вашем коде: по умолчанию minimumPressDuration
установлено значение 1000
по умолчанию, однако reset()
устанавливает значение в 1500
, что также может объяснить некоторые особенности вашего поведения.
class ForceTouchRecognizer: UIGestureRecognizer {
// The minimum time the touch should take
private let minimumTouchTime: TimeInterval = 2.0
// The start time of the touch
private var touchStartTime: TimeInterval?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
// Set the start time
touchStartTime = Date().timeIntervalSince1970
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
// If there is no start time, how is this possible, don't do anything
guard touchStartTime != nil else { return }
// Check if the minimumTouchTime has passed since the start time
if(Date().timeIntervalSince1970 - touchStartTime! > minimumTouchTime) {
print("I should perform some action now!")
}
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
// Make sure the start time is reset
touchStartTime = nil
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
// Make sure the start time is reset
touchStartTime = nil
}
}
Я бы также рекомендовал взглянуть на класс UILongPressGestureRecognizer. У этого также может быть некоторая функциональность, которая вам нужна.
Комментарии:
1. Большое спасибо. Я попробовал ваш код, и он работает! Я думаю, что ключ в том, чтобы убрать условие «holdFor> minimumPressDuration» из проверки состояния.