Обмен изображениями UIImageView в цикле - PullRequest
0 голосов
/ 05 февраля 2009

У меня есть NSArray UIImageViews, который я хочу зациклить и быстро поменять состояние «включено» и «выключено». Я написал код для этого в цикле for вместо метода, который вызывался, когда пользователь нажимал UIButton (действие кнопки).

Вот этот цикл:

for(int i = 0; i < [Images count]; i++) {
    if( i > 0 ){
        [self toggleImageViewOff:[Images objectAtIndex:i - 1]];
    }

    [self toggleImageViewOn:[Images objectAtIndex:i]];

    [NSThread sleepForTimeInterval:0.5f];
}

Пользовательский интерфейс не обновился, как я ожидал, поскольку я только когда-либо видел последний UIImageView во включенном состоянии. Я подумал, что обновление рисунка представлений должно происходить в основном потоке, в котором этот код также выполняется. Поэтому я узнал о executeSelectorInBackground: withObject:. Выполнение методов toggleImageViewOn / Off с использованием этого заставило цикл работать. Проблема в том, что если я сделаю интервал сна слишком коротким, я смогу получить обновление «включено» после «выключено» с потоками, работающими не по порядку.

Итак, у меня появилась блестящая идея переместить весь цикл со сном в его собственный метод и вызвать его из метода действия с помощью executeSelectorInBackground: withObject:. Я попробовал это, и я вернулся к тому, чтобы не получать обновленное представление, пока цикл не закончится.

Это долгий путь к моему вопросу:

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

Я пытался подумать о том, как мне это сделать с CoreAnimation, но я не могу понять, как это сделать там.

Для получения бонуса используйте следующие методы переключения:

- (void)toggleImageViewOn:(UIImageView *)theImageView {
    [theImageView setImage:[UIImage imageNamed:@"on.png"]];
}

- (void)toggleImageViewOff:(UIImageView *)theImageView {
    [theImageView setImage:[UIImage imageNamed:@"off.png"]];
}

Ответы [ 6 ]

2 голосов
/ 05 февраля 2009

Вы установили контекст анимации (метод класса UIView делает это) вокруг цикла for? Без этого изменения мгновенные, а не анимированные.

1 голос
/ 06 февраля 2009

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

Спящий основной поток фактически не дает ему возможности работать.

Билл прав в том, что вам нужно настроить анимационный контекст вокруг вашего цикла. Это запишет все сделанные вами изменения UIView, а затем воспроизведет их. Самый простой способ сделать это - использовать Core Animation. Основная анимация «записывает» изменения в UIElemenets и воспроизводит их. Ваш код (без сна) будет отлично работать в блоке Core Animation.

У Apple есть разумная кулинарная книга для Core Animation на их сайте

0 голосов
/ 06 февраля 2009

Вызов peformSelectorOnMainThread: withObject: waitUntilDone: из цикла в фоновом потоке действительно обновляет представление так быстро, как я думаю, мне когда-нибудь понадобится. Мне любопытно, почему мне нужно сделать обмен UIImageView на основной поток? Почему бы не изменить его в фоновом потоке, а затем использовать sleepForTimeInterval NSThread, чтобы основной поток все равно обновил чертеж?

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

Большое спасибо за помощь. (Я также собираюсь попробовать некоторые дополнительные предложения от Билла Дадни, которые, я думаю, будут работать на основе CoreAnimation)

0 голосов
/ 06 февраля 2009

Вы на правильном пути, переместив цикл в фоновый поток, но вам также нужно убедиться, что вы даете основному циклу выполнения шанс обновить пользовательский интерфейс. Вы должны иметь возможность заменить прямые вызовы toggleImageViewOn: и toggleImageViewOff: чем-то вроде

[self performSelectorOnMainThread:@selector(toggleImageViewOn:) withObject:[Images objectAtIndex:i] waitUntilDone:NO];

Это выполнит обновление пользовательского интерфейса в основном потоке, и, не дожидаясь завершения обновления, вы дадите основному циклу выполнения возможность достичь своего конца. Вы сталкиваетесь с той же проблемой с такими вещами, как индикаторы выполнения, где они не изменятся, пока цикл не закончится, если вы не выполните обновления из фонового потока с помощью вызова обновления пользовательского интерфейса, подобного приведенному выше.

0 голосов
/ 05 февраля 2009

Спасибо за это. Я уже изучил свойство animationImages в UIIMageView. Это не совсем то, что я пытаюсь сделать. Я переключаюсь между несколькими UIImageView, которые расположены рядом друг с другом, чтобы создать впечатление, что свет движется между ними и вращается над ними. Поэтому анимация отдельного UIImageView отделена друг от друга, так как мне нужно поменять местами изображение в коде.

0 голосов
/ 05 февраля 2009

Привет, Патрик. Посмотрите на свойство animationImages UIImageView, а также свойства animationRepeatCount и animationDuration. Если вы включаете / выключаете изображения в массив и назначаете его как свойство animationImages, вы должны иметь возможность контролировать повторение и продолжительность, чтобы получить желаемый эффект.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...