Android Animation: Подождите, пока не закончите?
Я хотел бы подождать, пока анимация закончится * в Android ImageView до продолжения выполнения программы, каков правильный способ сделать это?
- (в этом контексте "законченный" означает, что он проходит через все свои кадры ровно один раз и останавливается на последнем. Я не понимаю, будет ли эта анимация андроидом: onehot = "true", потому что я буду используя его несколько раз, но он не будет запускаться непрерывно, но с перерывами)
Исследования/Догадки:
а. На первый взгляд мой вопрос, кажется, вопрос Java-потока, потому что Android AnimationDrawable реализует Java.lang.Runnable. Поэтому, возможно, потоки являются решением. Возможно, ответ будет включать join?
В. Подход других, похоже, заключался в использовании AnimationListener, это кажется сложным и излишне сложным для моих простых потребностей. Плюс я не совсем уверен, как это сделать.
С. Класс AnimationDrawable имеет (boolean) метод isRunning, который, вероятно, можно использовать в цикле while (т.е. While (anim.isRunning() ) {ожидания (100мс)}). Но у меня есть ощущение, что это неправильный подход. Хотя что-то похожее упоминается в concurrency учебник
Фрагмент кода
this.q_pic_view.setImageResource(0);
this.q_pic_view.setBackgroundResource(R.drawable.animation_test);
AnimationDrawable correct_animation = (AnimationDrawable) this.q_pic_view.getBackground();
correct_animation.start();
//here I tried to implement option C but it didn't work
while(correct_animation.isRunning()){
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Анимация
<?xml version="1.0" encoding="utf-8"?>
<animation-list android:id="@+id/AnimTest" android:oneshot="true" xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/animtest001" android:duration="33"/>
<item android:drawable="@drawable/animtest002" android:duration="100"/>
<item android:drawable="@drawable/animtest003" android:duration="66"/>
<item android:drawable="@drawable/animtest004" android:duration="66"/>
<item android:drawable="@drawable/animtest005" android:duration="33"/>
<item android:drawable="@drawable/animtest006" android:duration="66"/>
<item android:drawable="@drawable/animtest007" android:duration="33"/>
<item android:drawable="@drawable/animtest008" android:duration="66"/>
<item android:drawable="@drawable/animtest009" android:duration="100"/>
<item android:drawable="@drawable/animtest010" android:duration="100"/>
</animation-list>
Один из возможных способов достижения желаемого эффекта, хотя и не ответ на мой вопрос, заключается в том, чтобы задержать выполнение дополнительного кода, выполнив что-то вроде этого:
int duration = 0;
//Add all of the frames together
for (int i=0; i<my_animation.getNumberOfFrames(); i++){
duration = duration + correct_animation.getDuration(i);
}
//delay the execution
Handler handler = new Handler();
handler.postDelayed(new Runnable(){
public void run() {
DoYourNextStuff();
}
}, duration); //delay is here
Изменить: Есть много способов решить эту проблему, ответ, вероятно, решает проблему, которую я не тестировал, но в итоге я просто ожидал правильного количества времени (сначала), затем я перешел на использование задача async (которая имеет метод обработчика для завершения) и запускала мою анимацию в вызове updateProgress задачи async напрямую. В последней итерации я использую резьбовое представление поверхности для запуска анимации. Этот последний путь, безусловно, самый быстрый и лучший (по другим причинам, о которых спрашивали в этом сообщении). Надеюсь, это поможет кому-то.
Ответы
Ответ 1
Предложите вам
- Создайте объект для инкапсуляции жизненного цикла анимации
- В объекте у вас будет поток или таймер
- Предоставьте методы
start()
анимации и awaitCompletion()
- Используйте поле
private final Object completionMonitor
для отслеживания завершения, synchronize
на нем и используйте wait()
и notifyAll()
для координации awaitCompletion()
Фрагмент кода:
final class Animation {
final Thread animator;
public Animation()
{
animator = new Thread(new Runnable() {
// logic to make animation happen
});
}
public void startAnimation()
{
animator.start();
}
public void awaitCompletion() throws InterruptedException
{
animator.join();
}
}
Вы также можете использовать ThreadPoolExecutor
с одним потоком или ScheduledThreadPoolExecutor
и захватить каждый кадр анимации как Callable
. Отправляя последовательность Callable
и используя invokeAll()
или CompletionService
, чтобы заблокировать ваш заинтересованный поток до завершения анимации.
Ответ 2
Самый простой способ - разместить (замедленный) Runnable для потока пользовательского интерфейса:
Animation fadeout = new AlphaAnimation(1.f, 0.f);
fadeout.setDuration(500);
view.startAnimation(fadeout);
view.postDelayed(new Runnable() {
@Override
public void run() {
view.setVisibility(View.GONE);
}
}, 500);
Это сделает работу безболезненно. И никогда (никогда, никогда, никогда!) Не пытайтесь заблокировать поток пользовательского интерфейса в Android. Если вы это сделаете, телефон замерзает, и вы все равно не увидите анимацию.
Если вам нужно подождать некоторое время, используйте другой поток.
Ответ 3
Используйте прослушиватель анимации для прослушивания анимационных циклов жизненного цикла.
Animation fadeout = new AlphaAnimation(1.f, 0.f);
fadeout.setDuration(500);
final View viewToAnimate = view;
fadeout.setAnimationListener(new AnimationListener(){
@Override
public void onAnimationStart(Animation animation){}
@Override
public void onAnimationRepeat(Animation animation){}
@Override
public void onAnimationEnd(Animation animation){
viewToAnimate.setVisibility(View.GONE);
}
});
view.startAnimation(fadeout);
Ответ 4
Привет, другие альтернативы используют ObjectAnimator. Опять же, как упоминалось выше, вам придется использовать Listner
//get an image resource
ImageView imgView = (ImageView) findViewById(R.id.some_image);
//create and init an ObjectAnimator
ObjectAnimator animation;
animation = ObjectAnimator.ofFloat(imgView, "rotationY", 0.0f, 360f);
//set the duration of each iteration
animation.setDuration(1500);
//set number of iterations
animation.setRepeatCount(1);
//set setInterpolator
animation.setInterpolator(new AccelerateDecelerateInterpolator());
//Add a listner to check when the animation ends
animation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
//postFirstAnimation(): This function is called after the animation ends
postFirstAnimation();
}
});
//start the animation
animation.start();