UISlider возвращает два события Touch Up Inside, почему это происходит?

У меня есть ползунок, который я использую, чтобы где-то установить значение с плавающей запятой. Я подключаю Value Changed к методу в моем viewController. Эта часть работает нормально.

Мне нужно знать, когда пользователь начинает касаться элемента управления, но не обязательно каждый раз, когда ползунок изменяется (для этого я получаю события Value Changed). Итак, я подключил событие Touch Up Inside к другому методу в viewController.

Проблема в том, что этот метод вызывается дважды, когда пользователь касается элемента управления UISlider. Какого черта? Это не работает с UIButtons или другими событиями касания, такими как Touch Down.

Я думаю, что могу обойти это, но это похоже на ошибку в том, как ползунок обрабатывает касания. Кто-нибудь знает, почему это происходит?

Кстати: событие двойного касания происходит, даже когда Touch Up Inside - единственное связанное событие.


person willc2    schedule 30.06.2009    source источник


Ответы (9)


Просто чтобы не нарушить будущие обновления

[customSlider addTarget:self action:@selector(sliderDown:) forControlEvents:UIControlEventTouchDown];

[customSlider addTarget:self action:@selector(sliderAction:) forControlEvents:UIControlEventTouchUpInside];



- (void)sliderDown:(id)sender
{

    sliderused = NO;

}

- (void)sliderAction:(id)sender
{
    if(sliderused){
    return;
}

sliderused = YES;

//Your Code Here
}
person bentech    schedule 24.06.2010

если вы хотите подклассифицировать слайдер, вы можете легко решить эту проблему, реализовав endTrackingWithTouch и ничего не делая:

- (void) endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{}

Единственное предостережение здесь в том, что некоторые определенные события UIControlEvents не будут запускаться должным образом. Я считаю, что это следующие, но я не проводил специального тестирования, чтобы увидеть, какие из них работают, а какие нет. однако прикосновение изменено и внутренняя подкраска определенно работают без дублирования срабатывания.

   UIControlEventTouchDragInside     = 1 <<  2,
   UIControlEventTouchDragOutside    = 1 <<  3,
   UIControlEventTouchDragEnter      = 1 <<  4,
   UIControlEventTouchDragExit       = 1 <<  5,
person jason    schedule 01.04.2010

У меня тоже была эта проблема, я решил добавить логическое значение «allowEvent». Затем я подключил UIControlEventTouchDown к функции, которая установила для параметра allowEvent значение YES.

В селекторе для UIControlEventTouchUpInside я проверил, имеет ли allowEvent значение YES, затем выполнил событие и установил для allowEvent значение NO.

Тогда событие будет выполнено только один раз, даже если оно сработает дважды.

Надеюсь, поможет!

person Community    schedule 20.08.2009

Я думаю, что самым простым решением является использование упомянутого выше флагового решения.

Я создал флаг под названием (BOOL) нажат и добавил к событиям TouchUpInside и TouchDown. Итак, вам просто нужно проверить, нажата ли кнопка == ДА.

// On down event
pressed = YES;

// On up event
if (pressed)
{
  pressed = NO;
  // code here

}

Я надеюсь, что это помогает.

Хами

person Hamiseixas    schedule 31.08.2009

Спасибо вам всем. У меня такая же проблема. Вот некоторая целочисленная математика, которая решает эту проблему за меня:

    static UInt32 counter = 0;

counter++;

if((counter/2)*2 != counter) return;
person Dan Selig    schedule 05.01.2010
comment
Ой! Что это должно значить? Только вернуть, если число четное? Лучше сделай if (counter % 2 == 0) return; вместо этого. - person DarkDust; 17.11.2010
comment
Что произойдет, когда Apple исправит эту ошибку, не испортит ли это решение ваше приложение? Я настоятельно рекомендую установить флаг, как предложено ниже Bentech. - person AlBeebe; 16.01.2011

Я только что попробовал и заметил такое же поведение. Он вызывается из двух мест: сначала из метода endTrackingWithTouch: withEvent: UISlider (который вызывается методом touchesEnded: withEvent: UIControl), а затем из того же метода touchesEnded: withEvent: UIControl (который сначала вызвал метод endTrakingWithTouch: withEvent:) .

Кроме того, когда касание закончилось за пределами ползунка, метод вызывается только один раз методом endTrackingWithTouch: withEvent:. Метод touchesEnded: withEvent: вызывает это, но затем не вызывает обратный вызов, как это было, когда касание завершилось внутри элемента управления.

Во всяком случае, зачем вы подключаете Touch Up Inside? Вы хотите знать, когда пользователь начинает касаться элемента управления, верно? Я думаю, вам тогда следует подключить Touch Down вместо Touch Up Inside.

Изменить: я вижу, что вам нужно измененное значение, и это измененное значение вызывается слишком часто. Я только что перепроверил тест и заметил следующее. Измененное значение вызывается между двумя внутренними вызовами ретуши. Может, с этим можно что-нибудь сделать?

person drvdijk    schedule 01.07.2009
comment
Мне нужно что-то делать после того, как слайд закончен. Touch Down срабатывает до завершения скольжения, а Value Changed срабатывает всякий раз, когда происходит скольжение, что происходит слишком часто. - person willc2; 01.07.2009
comment
Я изменил свой исходный ответ :) - person drvdijk; 01.07.2009

Поскольку мой предыдущий комментарий не был хорошо воспринят, я решил придумать простой способ решения проблемы на случай, если кому-то это интересно.

Я знаю, что это не самое эффективное решение в мире, но оно работает точно так же.

Я создал два метода: sliderUp и sliderChanged, связанные с TouchUp и ValueChanged соответственно. Я также создал глобальную переменную int (timesFired, если хотите), изначально установленную на ноль.

В методе sliderUp я помещаю любой код, который не возражаю запустить дважды. В моем случае я снимаю ползунок обратно вниз, если он не вверху (например, функция сдвига для разблокировки). Я также сбрасываю timeFired обратно на ноль после задержки. чтобы разрешить вызов другого метода. так, на всякий случай. (performSelector: withObject: afterDelay: если вы не знаете, как это сделать)

В методе sliderChanged у меня сначала есть оператор if: if (timesFired ‹1) {} (у меня также есть оператор if, чтобы убедиться, что мой ползунок находится на максимальном уровне), а затем включаю весь код, который я хочу выполнить только один раз , когда ползунок достигает максимального значения. чтобы убедиться, что этот код запускается только один раз, я также увеличиваю timesFired.

Как только пользователь поднимет палец на кнопку, timesFired вернется к нулю, и весь процесс может начаться заново.

Теперь, когда я смогу понять, как «заморозить» ползунок после того, как он попадет в верхнюю часть страницы, я действительно буду доволен этим решением. (просто отключение будет работать?)

person Community    schedule 25.07.2009

Эта ошибка исправлена ​​в версии 4.2. Теперь я использую код Дэна следующим образом:

static UInt32 counter = 0;

if ([[UIDevice currentDevice].systemVersion compare: @"4.2" options: NSNumericSearch] == NSOrderedAscending) {
    counter++;
    if((counter/2)*2 != counter) return;
}
person Ivan Leider    schedule 25.10.2010
comment
Ага! Зачем делить и умножать только для того, чтобы различать четное и нечетное? Используйте по модулю! if (counter % 2 == 0) return; - person DarkDust; 17.11.2010

Простое решение, которое не сломается, если Apple исправит эту ... функцию (?) В будущем, - это добавить свойство, в котором хранится время с момента последнего взаимодействия. и выйти, если с момента последнего взаимодействия прошло слишком много времени.

(в приведенном ниже коде latestTimeMark изначально установлен на текущее время в viewDidLoad)

NSDate *now = [NSDate date];
 double nowDouble = [now timeIntervalSince1970];
 double difference = nowDouble - self.latestTimeMark;
 self.latestTimeMark = nowDouble;
 //NSLog(@"difference is now: %f", difference);
 if(difference<0.01f) return;
person user351135    schedule 26.05.2010