English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Используя приложение Wallet, я обнаружил, что анимация запуска очень забавная, поэтому я решил имитировать её реализацию.
Эффект анимации gif:
animation.gif
Путь к реализации:
Если внимательно посмотреть, можно увидеть, что выполнение анимации делится на два этапа:
Первая фаза - падение монеты.
Вторая фаза -反弹 кошелька.
Layout xml файл如下:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <ImageView android:id="@+id/coin_iv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@mipmap/coin"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginBottom="70dp" android:layout_marginLeft="70dp" android:src="@mipmap/version"/> <ImageView android:id="@+id/wallet_iv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@mipmap/wallet"/> <Button android:id="@+id/start_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center|bottom" android:layout_marginBottom="10dp" android:text="start"/> </FrameLayout>
Падение монеты:
Во время падения монеты выполняются два типа анимаций: перемещение и вращение.
Анимация перемещения использует интерполяцию, xml-файл следующий:
<?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:fromYDelta="-50%p" android:interpolator="@android:anim/accelerate_interpolator" android:toYDelta="0%"/>
Ротационная анимация реализована через перезапись класса Animation и использование класса android.hardware.Camera.
public class ThreeDRotateAnimation extends Animation { int centerX, centerY; Camera camera = new Camera(); @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); // координаты центра centerX = width / 2; centerY = height / 2; setDuration(500); setInterpolator(new LinearInterpolator()); } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { final Matrix matrix = t.getMatrix(); camera.save(); // вращение вокруг оси Y camera.rotateY(360 * interpolatedTime); camera.getMatrix(matrix); // установка центра поворота matrix.preTranslate(-centerX, -centerY); matrix.postTranslate(centerX, centerY); camera.restore(); } }
Здесь кратко介绍一下 методы preTranslate и postTranslate в animation, preTranslate означает перед вращением rotateY выполнять перевод, а postTranslate означает выполнять перевод после rotateY, обратите внимание, что их параметры — это расстояние перевода, а не координаты цели перевода!
Поскольку вращение происходит вокруг центра (0,0), чтобы центрировать центр монеты с (0,0), необходимо выполнить preTranslate(-centerX, -centerY), после выполнения rotateY вызывается postTranslate(centerX, centerY), чтобы вернуть изображение обратно, и именно так видна анимация, где монета постоянно вращается вокруг центра.
В конце выполняются оба типа анимаций, чтобы был достигнут эффект падения и вращения.
private void startCoin() { // падение Animation animationTranslate = AnimationUtils.loadAnimation(this, R.anim.anim_top_in); // вращение ThreeDRotateAnimation animation3D = new ThreeDRotateAnimation(); animation3D.setRepeatCount(10); AnimationSet animationSet = new AnimationSet(true); animationSet.setDuration(800); animationSet.addAnimation(animation3D); animationSet.addAnimation(animationTranslate); mCoinIv.startAnimation(animationSet); }
钱包反弹:
在执行硬币掉落的同时,启动一个ValueAnimator动画,来判断钱包反弹的时机。
private void setWallet() { final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); valueAnimator.setDuration(800); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float fraction = animation.getAnimatedFraction(); // 大概掉落到钱包的上边缘位置的时候,取消ValueAnimator动画,并执行钱包反弹效果 if (fraction >= 0.75) { valueAnimator.cancel(); startWallet(); } }}); valueAnimator.start(); }
最后执行钱包反弹效果动画,这里采用了ObjectAnimator 。
private void startWallet() { // x轴缩放 ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(mLogoIv, "scaleX", 1, 1.1f, 0.9f, 1); objectAnimator1.setDuration(600); // y轴缩放 ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mLogoIv, "scaleY", 1, 0.75f, 1.25f, 1); objectAnimator2.setDuration(600); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.setInterpolator(new LinearInterpolator()); // Одновременное выполнение анимации масштабирования по осям x и y animatorSet.playTogether(objectAnimator1, objectAnimator2); animatorSet.start();}
Эффект анимации простого запуска钱包差不多 готов, единственный недостаток - при масштабировании кошелька по оси y, масштабируется вся ось y. Чтобы не двигать нижнюю часть кошелька, необходимо поднять верхнюю часть кошелька, пока не думал о хорошем способе, малый брат не очень умный, надеюсь, что великие мастера дадут советы! Спасибо!
Полный исходный код:
Полный исходный код находится вGitHub
Если вам это нравится, не забудьте starred╰( ̄▽ ̄)╮!
Вот и все, что есть в этой статье, я надеюсь, что это поможет вам в изучении. Надеюсь, что вы также поддержите и хлопайте в ладоши руководству Yell.
Заявление: контент этой статьи взят из Интернета, авторские права принадлежат соответствующему автору, контент предоставлен пользователями Интернета, сайт не обладает правами собственности, не был обработан редакторами, и не несет ответственности за соответствующие юридические последствия. Если вы обнаружите содержимое,涉嫌侵犯版权, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (при отправке письма, пожалуйста, замените # на @) для отчета,并提供相关证据. При обнаружении факта нарушения, сайт немедленно удаляет涉嫌侵权的内容。