安卓中关于属性动画的复合使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq77485042/article/details/77992032

这里写图片描述
这里写图片描述
以下是图片素材:
box_one
box_two
box_three
open_box_bg1
open_box_bg2
open_box_bg3
open_box_bg4
open_box_bg5
最近项目中用到这两个动画,花了一天的时间做出来,感觉也没有想象中的那么难,就好像开发过程中思路要一步步理清楚,然后抽丝剥茧的把动画一个一个组合起来就OK了。

我在这里用到的是属性动画配合幀动画来实现的,当然也可以使用补间动画来实现。在这里我就不过多介绍补间动画了。

先说说打开宝箱的动画的实现思路吧!!!

1.先得把一张张图片摆好位置,使用FrameLayout布局使其可以重叠

2.把所有的View压缩至看不见也就是相当于影藏起来,关键调用了setScaleX(0f)和setScaleY(0f)方法使其影藏

3.控件慢慢变大也就是一个个的缩放动画,背景的不停旋转也就是旋转动画,宝箱左右摇晃,也就是一个旋转动画,最后宝箱中跳出来的奖励也就是一个缩放加平移动画

4.打开宝箱的过程这个动画是没法使用属性动画完成的,所以我在这里添加了一个幀动画,总共有三幀。

好了思路理清楚了我就直接上代码了:

/**
 * Created by ${tanlei} on 2017/9/13.
 * 打开宝箱的dialog
 */

public class OpenBoxDialog extends Dialog {
    /**
     * 背景图片
     */
    private ImageView ivOpenBoxBg1, ivOpenBoxBg2, ivOpenBoxBg5;
    /**
     * 宝箱图片
     */
    private ImageView ivBox;
    /**
     * 奖励背景
     */
    private LinearLayout llLayout;
    private Context context;

    public OpenBoxDialog(@NonNull Context context) {
        this(context, 0);
    }

    public OpenBoxDialog(@NonNull Context context, @StyleRes int themeResId) {
        super(context, R.style.DialogTheme_no_systembar);
        this.context = context;
        View view = LayoutInflater.from(context).inflate(R.layout.open_box_dialog, null);
        setContentView(view);
        ivOpenBoxBg1 = (ImageView) view.findViewById(R.id.open_box_bg1);
        ivOpenBoxBg2 = (ImageView) view.findViewById(R.id.open_box_bg2);
        ivBox = (ImageView) view.findViewById(R.id.iv_box);
        llLayout = (LinearLayout) view.findViewById(R.id.ll);
        ivOpenBoxBg5 = (ImageView) view.findViewById(R.id.open_box_bg5);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        hideView();
        startBgAnimation();
    }

    /**
     * 开始动画
     */
    private void startBgAnimation() {
        AnimatorSet set = new AnimatorSet();
        AnimatorSet bg1Set = scaleAnimatorView(ivOpenBoxBg1);
        AnimatorSet boxSet = scaleAnimatorView(ivBox);
        //设置每个缩放动画的延迟执行的毫秒值差,来实现先后播放的视觉效果
        boxSet.setStartDelay(250);
        AnimatorSet bg2Set = scaleAnimatorView(ivOpenBoxBg2);
        bg2Set.setDuration(1500);
        bg2Set.setStartDelay(400);
        //宝箱左右摇晃动画
        ObjectAnimator rotationBoxAnimator = ObjectAnimator.ofFloat(ivBox, "rotation", 0f, -10f, 0f, 10f, 0f);
        rotationBoxAnimator.setStartDelay(750);
        rotationBoxAnimator.setDuration(400);
        //给摇晃动画设置监听器,使用AnimatorListenerAdapter就可以不需要实现所有的抽象方法,这里我只需要重写动画结束后的监听
        rotationBoxAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                //摇晃结束后执行打开宝箱的桢动画
                ivBox.setImageResource(R.drawable.open_box);
                AnimationDrawable frameAnimation = (AnimationDrawable) ivBox.getDrawable();
                frameAnimation.start();

                int duration = 0;
                for (int i = 0; i < frameAnimation.getNumberOfFrames(); i++) {
                    duration += frameAnimation.getDuration(i);
                }
                Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    public void run() {
                        //幀动画执行完成后
                        AnimatorSet set = new AnimatorSet();
                        AnimatorSet set2 = new AnimatorSet();
                        AnimatorSet set3 = new AnimatorSet();
                        //箱子中的白色光圈的缩放动画
                        ObjectAnimator bg1ScaleX = ObjectAnimator.ofFloat(ivOpenBoxBg5, "scaleX", 0f, 1f);
                        ObjectAnimator bg1ScaleY = ObjectAnimator.ofFloat(ivOpenBoxBg5, "scaleY", 0f, 1f);
                        bg1ScaleX.setDuration(150);
                        bg1ScaleY.setDuration(150);
                        set2.playTogether(bg1ScaleX, bg1ScaleY);
                        //箱子中的白色光圈消失的透明度动画
                        ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(ivOpenBoxBg5, "alpha", 1f, 0f);
                        //加速执行的加值器
                        alphaAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
                        //奖励布局的缩放动画
                        ObjectAnimator bg3ScaleX = ObjectAnimator.ofFloat(llLayout, "scaleX", 0f, 1f);
                        ObjectAnimator bg3ScaleY = ObjectAnimator.ofFloat(llLayout, "scaleY", 0f, 1f);
                        //奖励动画的平移
                        ObjectAnimator translationXAnimator = ObjectAnimator.ofFloat(llLayout, "translationY", 0f, 130f);
                        set3.playTogether(alphaAnimator, bg3ScaleX, bg3ScaleY, translationXAnimator);
                        set.playSequentially();
                        set3.setDuration(200);
                        set3.addListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation) {
                                super.onAnimationEnd(animation);
                                //奖励动画的平移结束后,得到动态布局中子View的个数,全部播放缩放动画
                                for (int i = 0; i < llLayout.getChildCount(); i++) {
                                    AnimatorSet animatorSet = scaleAnimatorView(llLayout.getChildAt(i));
                                    animatorSet.start();
                                }
                            }
                        });
                        set.playSequentially(set2, set3);
                        set.start();
                    }
                }, duration);

            }
        });
        set.playTogether(bg1Set, boxSet, bg2Set, rotationBoxAnimator);
        set.start();
    }

    /**
     * 缩放动画
     *
     * @param v
     * @return 返回一个动画集合
     */
    private AnimatorSet scaleAnimatorView(View v) {
        AnimatorSet set = new AnimatorSet();
        ObjectAnimator bg1ScaleX = ObjectAnimator.ofFloat(v, "scaleX", 0f, 1.2f, 1f);
        ObjectAnimator bg1ScaleY = ObjectAnimator.ofFloat(v, "scaleY", 0f, 1.2f, 1f);
        //如果是背景太阳光圈的话,需要缩放加旋转动画
        if (v.getId() == R.id.open_box_bg2) {
            ObjectAnimator animator = ObjectAnimator.ofFloat(v, "rotation", 0f, 360f);
            //匀速播放加值器,不然会出现旋转一圈后卡顿一会的效果
            animator.setInterpolator(new LinearInterpolator());
            //无限循环
            animator.setRepeatCount(-1);
            //一起播放
            set.playTogether(bg1ScaleX, bg1ScaleY, animator);
        } else {
            set.playTogether(bg1ScaleX, bg1ScaleY);
        }
        //动画集合播放事件
        set.setDuration(500);
        return set;
    }

    /**
     * 因为宝箱中的奖励数量和种类是不可控的,所以需要动态的添加View
     *
     * @param res
     */
    public void addView(int res) {
        ImageView imageView = new ImageView(context);
        imageView.setImageResource(res);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        params.gravity = Gravity.CENTER;
        params.weight = 1f;
        imageView.setLayoutParams(params);
        scaleView(imageView);
        llLayout.addView(imageView);
    }

    /**
     * 把View影藏掉
     */
    private void hideView() {
        scaleView(ivBox);
        scaleView(ivOpenBoxBg1);
        scaleView(ivOpenBoxBg2);
        scaleView(llLayout);
        scaleView(ivOpenBoxBg5);
    }

    private void scaleView(View view) {
        view.setScaleX(0f);
        view.setScaleY(0f);
    }
}

布局代码:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/open_box_bg1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@drawable/open_box_bg1" />

    <ImageView
        android:id="@+id/open_box_bg2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@drawable/open_box_bg2" />

    <ImageView
        android:id="@+id/iv_box"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_gravity="center"
        android:layout_marginBottom="20dp"
        android:scaleType="fitXY"
        android:src="@drawable/box_one" />

    <ImageView
        android:id="@+id/open_box_bg5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginBottom="20dp"
        android:src="@drawable/open_box_bg5" />

    <LinearLayout
        android:id="@+id/ll"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginBottom="20dp"
        android:background="@drawable/open_box_bg3"
        android:orientation="horizontal">

    </LinearLayout>
</FrameLayout>

幀动画代码:

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">
    <item
        android:drawable="@drawable/box_one"
        android:duration="50" />
    <item
        android:drawable="@drawable/box_two"
        android:duration="50" />
    <item
        android:drawable="@drawable/box_three"
        android:duration="50" />

</animation-list>

调用的代码:

OpenBoxDialog dialog = new OpenBoxDialog(this);
                dialog.addView(R.drawable.open_box_bg4);
                dialog.addView(R.drawable.open_box_bg4);
                dialog.show();

这里我对代码就不过多的解释了,就是一些简单的用法组合起来。

这里主要说一下为动画配置监听器的时候不要傻颠颠的使用addListener(new Animator.AnimatorListener()而是使用addListener(new AnimatorListenerAdapter())这是官方帮我们实现好了的适配器,你可以根据选择监听哪个事件就重写哪个方法。

还有这个playTogether()方法,可以把所有的动画对象丢至这个方法中,就可以一起执行,而不需要play().with()了,还有playSequentially()方法,把动画一个个丢进去就会按顺序一个一个执行过来,我这里就是使用到了playTogether()方法,把所有动画一起播放,只不过设置了动画的延迟播放时间来实现先后顺序。

如有错误或遗漏,请留言指出。

猜你喜欢

转载自blog.csdn.net/qq77485042/article/details/77992032
今日推荐