2015-07-01 2 views
0

Я реализовал UIProgressView в качестве таймера обратного отсчета, его значение уменьшилось с 1,0 до 0,0 за 1,5 секунды.Сделать UIProgressView как таймер обратного отсчета

Он уже работал, но проблема в том, сколько времени потребовалось больше, чем 1,5 секунд, это было около 2,0 - 2,5 секунды, пока значение зрения прогресс достигнет 0,0

Для того, чтобы работать в только 1,5, я уменьшил значение прогресса на 0.001 каждый раз, когда оно вызывается. Метод уменьшения - это вызов после интервала 0,0015 секунды.

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

- (void)decreaseProgress { 
    if (currentProgress > 0.0000f) { 
     currentProgress -= 0.001f; 
     [_timeLineProgress setProgress:currentProgress animated:YES]; 

     [self performSelector:@selector(decreaseProgress) withObject:self afterDelay:0.0015 inModes:@[NSDefaultRunLoopMode]]; 
    } else { 
     [self stopTimer]; 
    } 
} 
+0

Вы должны использовать NSTimer вместо и основывать прогресс на реальное истекшее время. – rmaddy

+0

@rmaddy это сделает какие-то большие различия? Потому что я использовал NSTimer, но все же получил ту же проблему. – JozackOverFlow

+0

Вот почему прогресс должен основываться на фактическом прошедшем времени, а не на каком-то увеличенном значении. – rmaddy

ответ

1

Вы пытаетесь обновить представление прогресса 1000 раз за 1,5 секунды. Это слишком быстро, так как экран обновляется только 60 раз в секунду. Другими словами, вы обновляете индикатор выполнения более 10 раз между каждым раз, когда индикатор выполнения фактически перерисовывается на экране.

Вместо этого я бы предложил 15 обновлений с интервалом 0,1 секунды и каждый раз изменял индикатор выполнения на 1/15.

Один из способов проверить, насколько хорошо выполняется код, использовать функцию CACurrentMediaTime для получения временных меток. Вот пример кода, который демонстрирует, как это сделать. Переменная progressStart - это метка времени, когда произошло событие нажатия кнопки, а NSLog печатает количество времени, прошедшего относительно времени начала.

Важная особенность кода заключается в том, что метод performSelector вызывается как можно раньше в методе updateProgress, чтобы минимизировать проскальзывание.

@interface ViewController() 
{ 
    CFTimeInterval progressStart; 
    int progressCount; 
} 
@property (weak, nonatomic) IBOutlet UIProgressView *progressView; 
@end 

- (void)updateProgress 
{ 
    if (progressCount > 0) 
     [self performSelector:@selector(updateProgress) withObject:nil afterDelay:0.1]; 

    self.progressView.progress = progressCount/15.0; 
    NSLog(@"%2d %.3lf", progressCount, CACurrentMediaTime() - progressStart); 
    progressCount--; 
} 

- (IBAction)someButtonPressed 
{ 
    self.progressView.progress = 1.0; 
    progressStart = CACurrentMediaTime(); 
    progressCount = 15; 
    [self updateProgress]; 
} 

А вот результаты типичного прогона

2015-07-01 13:05:57.610 Progress[8354:907] 15 0.000 
2015-07-01 13:05:57.711 Progress[8354:907] 14 0.101 
2015-07-01 13:05:57.813 Progress[8354:907] 13 0.203 
2015-07-01 13:05:57.914 Progress[8354:907] 12 0.304 
2015-07-01 13:05:58.015 Progress[8354:907] 11 0.405 
2015-07-01 13:05:58.116 Progress[8354:907] 10 0.506 
2015-07-01 13:05:58.218 Progress[8354:907] 9 0.608 
2015-07-01 13:05:58.319 Progress[8354:907] 8 0.709 
2015-07-01 13:05:58.420 Progress[8354:907] 7 0.810 
2015-07-01 13:05:58.520 Progress[8354:907] 6 0.910 
2015-07-01 13:05:58.621 Progress[8354:907] 5 1.011 
2015-07-01 13:05:58.722 Progress[8354:907] 4 1.112 
2015-07-01 13:05:58.823 Progress[8354:907] 3 1.213 
2015-07-01 13:05:58.924 Progress[8354:907] 2 1.314 
2015-07-01 13:05:59.024 Progress[8354:907] 1 1.415 
2015-07-01 13:05:59.125 Progress[8354:907] 0 1.515 

Следует отметить, что метод имеет около 1 миллисекунды проскальзывания по каждому событию. Общее проскальзывание составляло 15 миллисекунд. Скорость обновления экрана устройства составляет 60 кадров/с, что составляет 16,7 мс/фрейм. Таким образом, общее проскальзывание было меньше одного времени кадра и не будет заметным для пользователя.

Как отметил rmaddy в комментариях, использование NSTimer позволяет избежать большей части проскальзывания. Тем не менее, последнее событие таймера все равно может скользить на произвольное время.

+0

Спасибо за ваш ответ, я просто попробовал вас, но индикатор выполнения все еще работает через 2 секунды. Я не знаю почему? – JozackOverFlow

+1

Это зависит от того, что еще делает система. Метод 'performSelector: afterDelay' определяет только минимальную задержку. Фактическая задержка может быть больше, если система занята. – user3386109

+0

Таким образом, нет никакого способа заставить его работать ровно 1,5 секунды? – JozackOverFlow

3

Чтобы оживить прогресс, попробуйте этот код в методе decreaseProgress

[UIView animateWithDuration:1.5 animations:^{ 
     [_timeLineProgress setProgress:0.0 animated:YES]; 
    }]; 
+0

Спасибо за ваше решение Vinay. Я думаю, что это сработает, но у меня есть еще несколько действий, пока прогресс работает, таким образом он может плавно анимироваться, но я не буду контролировать его в целом, что-то вроде сброса прогресса во время его работы. – JozackOverFlow

Смежные вопросы