UISlider возвращает два события Touch Up Inside, почему это происходит? - PullRequest
6 голосов
/ 30 июня 2009

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

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

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

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

BTW : событие двойного касания происходит, даже если Touch Up Inside является единственным подключенным событием.

Ответы [ 9 ]

6 голосов
/ 24 июня 2010

Только для того, чтобы не допустить будущих обновлений

[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
}
2 голосов
/ 01 апреля 2010

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

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

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

   UIControlEventTouchDragInside     = 1 <<  2,
   UIControlEventTouchDragOutside    = 1 <<  3,
   UIControlEventTouchDragEnter      = 1 <<  4,
   UIControlEventTouchDragExit       = 1 <<  5,
1 голос
/ 06 января 2010

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

    static UInt32 counter = 0;

counter++;

if((counter/2)*2 != counter) return;
1 голос
/ 31 августа 2009

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

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

// On down event
pressed = YES;

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

}

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

Хами

1 голос
/ 21 августа 2009

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

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

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

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

0 голосов
/ 25 октября 2010

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

static UInt32 counter = 0;

if ([[UIDevice currentDevice].systemVersion compare: @"4.2" options: NSNumericSearch] == NSOrderedAscending) {
    counter++;
    if((counter/2)*2 != counter) return;
}
0 голосов
/ 26 мая 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;
0 голосов
/ 26 июля 2009

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

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

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

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

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

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

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

0 голосов
/ 01 июля 2009

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

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

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

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

...