我正在尝试创建一个有点复杂的动画,其中涉及同一布局中的多个视图。视图将改变大小,不透明度,并且需要同时播放所有的图像切换器。我已经通过使用ValueAnimator
来执行了必要的动画,但是动画跳过了太多的帧(可能是25帧),如果可能的话,它们需要以某种方式进行优化。
为了显示有关动画的一些详细信息,这是我的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<com.example.android.views.DragLayer xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<FrameLayout
android:id="@+id/containerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<!-- Target width is 60dp for animation view. -->
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/animationView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_gravity="center"
android:visibility="gone"
app:lottie_rawRes="@raw/bubble_loop_animation"
app:lottie_loop="true"
app:lottie_autoPlay="false" />
<!-- Target width is 50dp for progress view. -->
<com.example.android.views.ProgressView
android:id="@+id/progressView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_gravity="center"
android:visibility="gone"
app:useDefaultProgressColors="false"
app:strokeWidth="10dp"
app:strokeGradientStart="#FFC928"
app:strokeGradientEnd="#E53935" />
<!-- Width transition: from 28dp to 45dp
Height transition: from 28dp to 45dp
Alpha transition: from 0.35 to 1 -->
<View
android:id="@+id/gamepadBackgroundView"
android:layout_width="28dp"
android:layout_height="28dp"
android:background="@drawable/gamepad_background"
android:layout_gravity="center"
android:alpha="0.35" />
<!-- Width transition: from 19dp to 29dp
Height transition: from 14dp to 20dp -->
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/fireImageView"
android:layout_width="19dp"
android:layout_height="14dp"
android:layout_gravity="center"
app:srcCompat="@drawable/ic_fire" />
<!-- Width transition: from 14dp to 24dp
Height transition: from 9dp to 16dp
Remove marginTop on scale up and add on scale down -->
<ImageSwitcher
android:id="@+id/gamepadImageSwitcher"
android:layout_width="14.1dp"
android:layout_height="9.3dp"
android:layout_gravity="center"
android:layout_marginTop="5dp" />
</FrameLayout>
</com.burakgon.gamebooster3.views.DragLayer>
目标动画信息显示在布局文本上。要澄清更多:
setImageResource
进行更改。它的动画是淡出->淡入动画。marginTop
。com.example.android.views.DragLayer
视图也将更改大小。这些动画必须有相反的版本,我也成功实现了该动画,但是也会跳过帧。我说的是大块,有时我什至看不到动画。我在播放动画时正在使用View.LAYER_TYPE_HARDWARE
,但它们似乎也无济于事。所有视图大小的更改都使操作繁重,但是我不确定该如何做。
这是我尝试实现动画的方式。
// Required constants for animations.
static
{
ANIM_VIEW_SIZE_SMALL = 0;
ANIM_VIEW_SIZE_BIG = (int) dpToPx(60);
PROGRESS_VIEW_SIZE_SMALL = 0;
PROGRESS_VIEW_SIZE_BIG = (int) dpToPx(50);
GAMEPAD_BACKGROUND_SIZE_SMALL = (int) dpToPx(28);
GAMEPAD_BACKGROUND_SIZE_BIG = (int) dpToPx(45);
FIRE_ICON_WIDTH = (int) dpToPx(18);
FIRE_ICON_HEIGHT = (int) dpToPx(22);
IMAGE_SWITCHER_WIDTH_SMALL = (int) dpToPx(14);
IMAGE_SWITCHER_WIDTH_BIG = (int) dpToPx(24);
IMAGE_SWITCHER_HEIGHT_SMALL = (int) dpToPx(9);
IMAGE_SWITCHER_HEIGHT_BIG = (int) dpToPx(16);
IMAGE_SWITCHER_MARGIN_TOP = (int) dpToPx(5);
}
private void startAnimation()
{
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
animator.setDuration(ANIM_LONG);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
float value = animation.getAnimatedValue() != null ? (float) animation.getAnimatedValue() : 0f;
arrangeViewsToBiggerTransition(value);
updateTranslationValues();
}
});
animator.addListener(new AnimatorListenerAdapter()
{
@Override
public void onAnimationStart(Animator animation)
{
super.onAnimationStart(animation);
makeViewsVisible();
setLayerTypeHardware(progressView, gamepadBackgroundView,
gamepadImageSwitcher, fireImageView);
gamepadImageSwitcher.setImageResource(R.drawable.ic_game);
}
@Override
public void onAnimationEnd(Animator animation)
{
super.onAnimationEnd(animation);
resetLayerType(progressView, gamepadBackgroundView,
gamepadImageSwitcher, fireImageView);
animationView.playAnimation();
}
});
animator.addListener(getDeleteAnimatorListener());
animator.start();
}
private void setLayerTypeHardware(View... views)
{
for (View view : views)
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
private void resetLayerType(View... views)
{
for (View view : views)
view.setLayerType(View.LAYER_TYPE_NONE, null);
}
/**
* Arranges the views defined by percent. Changes from 0 to 1, not 0 to 100.
*
* @param percent is the value between 0 and 1.
*/
private void arrangeViewsToBiggerTransition(float percent)
{
float gamepadBackgroundAlpha = getValueByPercent(GAMEPAD_BACKGROUND_ALPHA, 1f, percent);
int animViewSize = (int) getValueByPercent(ANIM_VIEW_SIZE_SMALL, ANIM_VIEW_SIZE_BIG, percent);
int progressViewSize = (int) getValueByPercent(PROGRESS_VIEW_SIZE_SMALL, PROGRESS_VIEW_SIZE_BIG, percent);
int gamepadBackgroundViewSize = (int) getValueByPercent(GAMEPAD_BACKGROUND_SIZE_SMALL, GAMEPAD_BACKGROUND_SIZE_BIG, percent);
int imageSwitcherWidth = (int) getValueByPercent(IMAGE_SWITCHER_WIDTH_SMALL, IMAGE_SWITCHER_WIDTH_BIG, percent);
int imageSwitcherHeight = (int) getValueByPercent(IMAGE_SWITCHER_HEIGHT_SMALL, IMAGE_SWITCHER_HEIGHT_BIG, percent);
int imageSwitcherMarginTop = (int) getValueByPercent(IMAGE_SWITCHER_MARGIN_TOP, 0f, percent);
editViewSize(animationView, animViewSize, animViewSize);
editViewSize(progressView, progressViewSize, progressViewSize);
editViewSize(gamepadBackgroundView, gamepadBackgroundViewSize, gamepadBackgroundViewSize);
editViewSize(gamepadImageSwitcher, imageSwitcherWidth, imageSwitcherHeight, false);
editViewMarginTop(gamepadImageSwitcher, imageSwitcherMarginTop);
gamepadBackgroundView.setAlpha(gamepadBackgroundAlpha);
fireImageView.setAlpha(1f - percent);
}
/**
* Edits the view size and requests layout.
*/
private void editViewSize(View view, int width, int height)
{
editViewSize(view, width, height, true);
}
/**
* Edits the view size and requests layout.
*/
private void editViewSize(View view, int width, int height, boolean requestLayout)
{
if (view.getLayoutParams() != null)
{
view.getLayoutParams().width = width;
view.getLayoutParams().height = height;
if (requestLayout)
view.requestLayout();
}
}
/**
* Edits the view's margin top attribute and requests layout.
*/
private void editViewMarginTop(View view, int marginTop)
{
if (view.getLayoutParams() instanceof MarginLayoutParams)
{
((MarginLayoutParams) view.getLayoutParams()).topMargin = marginTop;
view.requestLayout();
}
}
/**
* Returns the calculated percentage value for start and end. Percent
* should be between 0 and 1.
*
* @param start is the start value.
* @param end is the end value.
* @param percent is between 0 and 1.
*
* @return (end - start) / percent
*/
private float getValueByPercent(float start, float end, float percent)
{
return start + ((end - start) * percent);
}
是否有任何优化建议?备择方案?感谢您的帮助,非常感谢。
DragLayer
上具有固定的宽度和高度(也称为根视图)解决了大多数问题:显然,当根视图包装内容时,重新布局的成本效益太高。因为我知道目标动画的最大宽度和最大高度,所以固定了根视图的宽度和高度,然后将居中的containerView
用作wrap_content
似乎已经解决了问题。