Android基础——Tween动画、Drawable动画、Property动画、MaterialDesign动画、Trasition动画

项目主页

这里写图片描述

项目结构

项目结构清晰,以介绍的模块对应起来

这里写图片描述

BaseActivity

这里会发现一个奇怪的Activity,每个Activity都继承这个BaseActivity,其作用就是增加标题和返回键的功能

这里写图片描述

public class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }

    @Override
    public boolean onSupportNavigateUp() {
        onBackPressed();
        return true;
    }
}

Tween动画

这里写图片描述

Tween动画比较简单,我们常说的平移、旋转、缩放、透明度这四个动画,其中可以将每个动画都搭配起来成为集合,Tween动画的展示形式有两种,一种通过xml形式,另一种是代码方式,由于比较简单,就不详细介绍了

代码形式

public class TweenActivity extends BaseActivity implements View.OnClickListener {

    private ImageView rectangle_red;
    private Switch isXml;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tween);

        rectangle_red = (ImageView) findViewById(R.id.rectangle_red);
        isXml = (Switch) findViewById(R.id.isXml);

        findViewById(R.id.translate).setOnClickListener(this);
        findViewById(R.id.rotate).setOnClickListener(this);
        findViewById(R.id.scale).setOnClickListener(this);
        findViewById(R.id.alpha).setOnClickListener(this);
        findViewById(R.id.set).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.translate:
                if (isXml.isChecked()) {
                    Animation anim = AnimationUtils.loadAnimation(this, R.anim.tween_translate);
                    rectangle_red.startAnimation(anim);
                    return;
                }
                //平移动画
                TranslateAnimation translateAnimation = new TranslateAnimation(0, 100, 0, 100);
                translateAnimation.setRepeatMode(Animation.REVERSE);
                translateAnimation.setFillAfter(true);
                translateAnimation.setDuration(2000);
                translateAnimation.setRepeatCount(1);
                rectangle_red.startAnimation(translateAnimation);
                break;
            case R.id.rotate:
                if (isXml.isChecked()) {
                    Animation anim = AnimationUtils.loadAnimation(this, R.anim.tween_rotate);
                    rectangle_red.startAnimation(anim);
                    return;
                }
                //旋转动画
                RotateAnimation rotateAnimation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, Animation.RELATIVE_TO_SELF);
                rotateAnimation.setRepeatMode(Animation.REVERSE);
                rotateAnimation.setFillAfter(true);
                rotateAnimation.setDuration(2000);
                rotateAnimation.setRepeatCount(1);
                rectangle_red.startAnimation(rotateAnimation);
                break;
            case R.id.scale:
                if (isXml.isChecked()) {
                    Animation anim = AnimationUtils.loadAnimation(this, R.anim.tween_scale);
                    rectangle_red.startAnimation(anim);
                    return;
                }
                //缩放动画
                ScaleAnimation scaleAnimation = new ScaleAnimation(1, 2, 1, 2, Animation.RELATIVE_TO_SELF, Animation.RELATIVE_TO_SELF);
                scaleAnimation.setRepeatMode(Animation.REVERSE);
                scaleAnimation.setFillAfter(true);
                scaleAnimation.setDuration(2000);
                scaleAnimation.setRepeatCount(1);
                rectangle_red.startAnimation(scaleAnimation);
                break;
            case R.id.alpha:
                if (isXml.isChecked()) {
                    Animation anim = AnimationUtils.loadAnimation(this, R.anim.tween_alpha);
                    rectangle_red.startAnimation(anim);
                    return;
                }
                //透明度动画
                AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0.5f);
                alphaAnimation.setRepeatMode(Animation.REVERSE);
                alphaAnimation.setFillAfter(true);
                alphaAnimation.setDuration(2000);
                alphaAnimation.setRepeatCount(1);
                rectangle_red.startAnimation(alphaAnimation);
                break;
            case R.id.set:
                if (isXml.isChecked()) {
                    Animation anim = AnimationUtils.loadAnimation(this, R.anim.tween_set);
                    rectangle_red.startAnimation(anim);
                    return;
                }
                //动画集合
                ScaleAnimation scaleAnim = new ScaleAnimation(1, 2, 1, 2, Animation.RELATIVE_TO_SELF, Animation.RELATIVE_TO_SELF);
                scaleAnim.setRepeatMode(Animation.REVERSE);
                scaleAnim.setFillAfter(true);
                scaleAnim.setDuration(2000);
                scaleAnim.setRepeatCount(1);

                AlphaAnimation alphaAnim = new AlphaAnimation(1, 0.5f);
                alphaAnim.setRepeatMode(Animation.REVERSE);
                alphaAnim.setFillAfter(true);
                alphaAnim.setDuration(2000);
                alphaAnim.setRepeatCount(1);

                AnimationSet set = new AnimationSet(true);
                set.addAnimation(scaleAnim);
                set.addAnimation(alphaAnim);
                rectangle_red.startAnimation(set);
                break;
        }
    }
}

Xml形式

如果是Xml形式的话,就必须在res目录下的anim目录下指定对应的动画xml文件,具体的内容可以查看源码

这里写图片描述

Drawable动画

这里写图片描述

Drawable也可以称为帧动画,就是通过一帧一帧的图片展示出来的动画,代码很简单,只需要开启动画就可以了

public class DrawableActivity extends BaseActivity implements View.OnClickListener {

    private AnimationDrawable background;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_drawable);

        findViewById(R.id.start).setOnClickListener(this);

        ImageView iv_arrow = (ImageView) findViewById(R.id.iv_arrow);
        iv_arrow.setBackgroundResource(R.drawable.drawable_anim);
        background = (AnimationDrawable) iv_arrow.getBackground();
    }

    @Override
    public void onClick(View v) {
        background.start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (background.isRunning()) {
            background.stop();
        }
    }
}

在布局文件中使用background属性即可

<ImageView
   android:id="@+id/iv_arrow"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_centerInParent="true"
   android:background="@drawable/drawable_anim" />

这个drawable_anim就是一长串的动画图片的声明

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">
    <item android:duration="16">
        <bitmap android:src="@drawable/ic_done_anim_000" />
    </item>
    <item android:duration="16">
        <bitmap android:src="@drawable/ic_done_anim_001" />
    </item>
    <item android:duration="16">
        <bitmap android:src="@drawable/ic_done_anim_002" />
    </item>
    <item android:duration="16">
        <bitmap android:src="@drawable/ic_done_anim_003" />
    </item>
    <item android:duration="16">
        <bitmap android:src="@drawable/ic_done_anim_004" />
    </item>
    <item android:duration="16">
        <bitmap android:src="@drawable/ic_done_anim_005" />
    </item>
    ......
</animation-list>

Property动画

这里写图片描述

Property动画分为两种

  • ObjectAnimator:ObjectAnimator将View的属性就行修改,使其产生动画,比如x坐标y坐标修改,就能形成平移
  • ValueAnimator:ValueAnimator会分配一个区间的值,随着值的增长或者下降,使用其产生的值进行更新动画
public class PropertyActivity extends BaseActivity implements View.OnClickListener {

    private ImageView rectangle_red;
    private Switch isXml;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_property);

        rectangle_red = (ImageView) findViewById(R.id.rectangle_red);
        isXml = (Switch) findViewById(R.id.isXml);

        findViewById(R.id.translate).setOnClickListener(this);
        findViewById(R.id.rotate).setOnClickListener(this);
        findViewById(R.id.scale).setOnClickListener(this);
        findViewById(R.id.alpha).setOnClickListener(this);
        findViewById(R.id.set).setOnClickListener(this);
        findViewById(R.id.setWay2).setOnClickListener(this);
        findViewById(R.id.translate2).setOnClickListener(this);
        findViewById(R.id.rotate2).setOnClickListener(this);
        findViewById(R.id.scale2).setOnClickListener(this);
        findViewById(R.id.alpha2).setOnClickListener(this);
        findViewById(R.id.set2).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.translate:

                if (isXml.isChecked()) {
                    Animator anim = AnimatorInflater.loadAnimator(this, R.animator.value_translate);
                    anim.setTarget(rectangle_red);
                    anim.start();
                    return;
                }

                ObjectAnimator.ofFloat(rectangle_red, "translationX", 0.0F, 150.0F)
                        .setDuration(1000)
                        .start();
                break;
            case R.id.rotate:

                if (isXml.isChecked()) {
                    Animator anim = AnimatorInflater.loadAnimator(this, R.animator.value_rotate);
                    anim.setTarget(rectangle_red);
                    anim.start();
                    return;
                }

                ObjectAnimator.ofFloat(rectangle_red, "rotationX", 0.0F, 360.0F)
                        .setDuration(1000)
                        .start();
                break;
            case R.id.scale:

                if (isXml.isChecked()) {
                    Animator anim = AnimatorInflater.loadAnimator(this, R.animator.value_scale);
                    anim.setTarget(rectangle_red);
                    anim.start();
                    return;
                }

                ObjectAnimator.ofFloat(rectangle_red, "scaleX", 1.0F, 3.0F)
                        .setDuration(1000)
                        .start();
                break;
            case R.id.alpha:

                if (isXml.isChecked()) {
                    Toast.makeText(this, "这个不行", Toast.LENGTH_SHORT).show();
                    return;
                }

                ObjectAnimator.ofFloat(rectangle_red, "alpha", 1F, 0.5F)
                        .setDuration(1000)
                        .start();
                break;
            case R.id.set:
                //动画集合
                if (isXml.isChecked()) {
                    Animator anim = AnimatorInflater.loadAnimator(this, R.animator.value_set);
                    anim.setTarget(rectangle_red);
                    anim.start();
                    return;
                }

                PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("scaleX", 1f, 0f, 1f);
                PropertyValuesHolder pvhScaleY = PropertyValuesHolder.ofFloat("scaleY", 1f, 0f, 1f);
                ObjectAnimator customAnim = ObjectAnimator.ofPropertyValuesHolder(rectangle_red, pvhScaleX, pvhScaleY);
                customAnim.setDuration(4000);
                customAnim.start();

                break;
            case R.id.setWay2:
                //动画集合2
                if (isXml.isChecked()) {
                    Animator anim = AnimatorInflater.loadAnimator(this, R.animator.value_set);
                    anim.setTarget(rectangle_red);
                    anim.start();
                    return;
                }

                ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(rectangle_red, "translationX", 0.0F, 150.0F).setDuration(1000);
                ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(rectangle_red, "translationY", 0.0F, 150.0F).setDuration(1000);
                ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(rectangle_red, "rotationX", 0.0F, 360.0F).setDuration(1000);
                AnimatorSet animatorSet = new AnimatorSet();
                animatorSet.setDuration(3000);
                // 随机设置
                animatorSet.play(objectAnimator1)
                        .with(objectAnimator2)
                        .after(objectAnimator3);
//                // 一起播放
//                animatorSet.playTogether(objectAnimator1, objectAnimator2, objectAnimator3);
//                // 顺序播放
//                animatorSet.playSequentially(objectAnimator1, objectAnimator2, objectAnimator3);
                animatorSet.start();
                break;
            case R.id.translate2:
                startValueAnimator(0);
                break;
            case R.id.rotate2:
                startValueAnimator(1);
                break;
            case R.id.scale2:
                startValueAnimator(2);
                break;
            case R.id.alpha2:
                startValueAnimator(3);
                break;
            case R.id.set2:
                startValueAnimator(4);
                break;
        }
    }


    /**
     * ValueAnimator
     */
    public void startValueAnimator(final int id) {
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(150)
                .setDuration(1000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                if (id == 0) {
                    rectangle_red.setTranslationX((Float) animation.getAnimatedValue());
                } else if (id == 1) {
                    rectangle_red.setRotation((Float) animation.getAnimatedValue());
                } else if (id == 2) {
                    rectangle_red.setScaleX((Float) animation.getAnimatedValue());
                } else if (id == 3) {
                    rectangle_red.setAlpha((Float) animation.getAnimatedValue());
                } else if (id == 4) {
                    rectangle_red.setTranslationX((Float) animation.getAnimatedValue());
                    rectangle_red.setScaleX((Float) animation.getAnimatedValue());
                    rectangle_red.setAlpha((Float) animation.getAnimatedValue());
                }
            }
        });
        valueAnimator.start();
    }
}

MaterialDesign动画

这里写图片描述

MaterialDesign动画分为两种

  • 水波纹动画
  • 揭露动画

水波纹动画

水波纹就是通过水波纹动画在xml上的编写,然后通过View设置background即可

<Button
    android:id="@+id/ripple"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/materia_ripple"
    android:text="Ripple" />

<Button
    android:id="@+id/ripple1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/materia_ripple1"
    android:text="Ripple1" />

<Button
    android:id="@+id/ripple2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/materia_ripple2"
    android:text="Ripple2" />

materia_ripple.xml

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/colorAccent">
</ripple>

materia_ripple1.xml

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/colorAccent">
    <item
        android:id="@android:id/mask"
        android:drawable="@android:color/holo_green_dark"/>
</ripple>

materia_ripple2.xml

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/colorAccent">
    <item
        android:id="@android:id/mask"
        android:drawable="@android:color/holo_green_dark"/>

    <item android:drawable="@color/colorPrimary"/>

</ripple>

揭露动画

揭露动画只要在通过代码生成即可

public class MaterialDesignActivity extends BaseActivity implements View.OnClickListener {

    private ImageView show_pic;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_material_design);


        show_pic = (ImageView) findViewById(R.id.show_pic);
        findViewById(R.id.reveal).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.reveal:
                //直径
                int d = Math.max(show_pic.getHeight(), show_pic.getWidth()) * 2;
                //参数1:view 参数2:x坐标 参数3:y坐标 参数4:动画开始的半径 参数:动画结束的半径
                Animator animator = ViewAnimationUtils.createCircularReveal(show_pic, 0, 0, 0, d);
                animator.setDuration(1000);
                animator.start();
                break;
        }
    }
}

Transition动画

这里写图片描述

Transition动画是目前比较流行的动画,包含以下内容

  • 转场动画
  • 共享元素动画

转场动画

系统默认为我们提供了三种转场动画,其实现步骤如下

1、在需要跳转的界面中,启动Activity的时候调用新的API

public class TransitionActivity extends BaseActivity implements View.OnClickListener {

    private Intent mIntent = new Intent();
    private Switch isXml;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_transition);

        isXml = (Switch) findViewById(R.id.isXml);

        findViewById(R.id.explode).setOnClickListener(this);
        findViewById(R.id.slide).setOnClickListener(this);
        findViewById(R.id.fade).setOnClickListener(this);
    }

    /**
     * 启动Activity
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.explode:
                mIntent.setClass(this, TransitionToThisActivity.class);
                mIntent.putExtra("transition", "explode");
                mIntent.putExtra("isXml", isXml.isChecked());
                startActivity(mIntent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
                break;
            case R.id.slide:
                mIntent.setClass(this, TransitionToThisActivity.class);
                mIntent.putExtra("transition", "slide");
                mIntent.putExtra("isXml", isXml.isChecked());
                startActivity(mIntent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
                break;
            case R.id.fade:
                mIntent.setClass(this, TransitionToThisActivity.class);
                mIntent.putExtra("transition", "fade");
                mIntent.putExtra("isXml", isXml.isChecked());
                startActivity(mIntent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
                break;
        }
    }
}

2、在跳转过去的界面中,设置进入动画和退出动画即可

public class TransitionToThisActivity extends BaseActivity {

    private String transition;
    private TextView textView;
    private boolean isXml;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_transition_to_this);

        transition = getIntent().getStringExtra("transition");
        isXml = getIntent().getBooleanExtra("isXml", false);
        initAnimation();
    }

    /**
     * 设置进入动画和退出动画
     */
    private void initAnimation() {
        textView = (TextView) findViewById(R.id.share_text);
        textView.setText(transition);

        switch (transition) {
            case "explode":

                if (isXml) {
                    Explode explode = (Explode) TransitionInflater.from(this).inflateTransition(R.transition.explode);
                    explode.setDuration(1000L);
                    getWindow().setEnterTransition(explode);
                    return;
                }

                Explode explode = new Explode();
                explode.setDuration(1000L);
                getWindow().setEnterTransition(explode);
                break;
            case "slide":

                if (isXml) {
                    Slide slide = (Slide) TransitionInflater.from(this).inflateTransition(R.transition.slide);
                    slide.setDuration(1000L);
                    getWindow().setEnterTransition(slide);
                    return;
                }

                Slide slide = new Slide(Gravity.BOTTOM);
                slide.setDuration(1000L);
                getWindow().setEnterTransition(slide);
                break;
            case "fade":

                if (isXml) {
                    Fade fade = (Fade) TransitionInflater.from(this).inflateTransition(R.transition.fade);
                    fade.setDuration(1000L);
                    getWindow().setEnterTransition(fade);
                    return;
                }

                Fade fade = new Fade();
                fade.setDuration(1000L);
                getWindow().setEnterTransition(fade);
                break;
            default:
                break;
        }
    }
}

共享元素

这里写图片描述

共享元素,其实现步骤如下

1、布局文件中设置view元素的共享字段,通过transitionName声明共享元素的字段

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/rectangle_red"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:background="@drawable/rectangle_red"
        android:transitionName="share" />

    <TextView
        android:id="@+id/share_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="18dp"
        android:gravity="center"
        android:text="Explode"
        android:transitionName="share_text" />

</LinearLayout>

2、启动Activity指定所有共享view元素

mIntent.setClass(this, TransitionToThisActivity.class);
mIntent.putExtra("transition", "share");

//5.0以上兼容的API
ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(this
        , Pair.create(findViewById(R.id.rectangle_red), "share")
        , Pair.create(findViewById(R.id.share_text), "share_text"));

//5.0以下兼容的API
ActivityOptionsCompat activityOptionsCompat1 = ActivityOptionsCompat.makeSceneTransitionAnimation(this
        , Pair.create(findViewById(R.id.rectangle_red), "share")
        , Pair.create(findViewById(R.id.share_text), "share_text"));

startActivity(mIntent, transitionActivityOptions.toBundle());

源码下载

源码下载

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

许英俊潇洒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值