Material Design5.x动画实现解析篇一

Material Design设计语言动画篇共推出六种类型的动画效果:

1、Touch feedback(触摸反馈)
2、Reveal effect(揭露效果)
3、Activity transitions(Activity转换效果)
4、Curved motion(曲线运动)
5、View state changes (视图状态改变)
6、Animate Vector Drawables(矢量动画)

触摸反馈

在Android 5.0以上,当我们设置了Material Design主题后,系统默认就有这种效果了,就是常说的水波纹效果,当触摸可点击的控件时,水波纹就会从触点慢慢的扩散开,如:
这里写图片描述
这种效果并不需要我们自己设置,默认就是上图那种效果,不过我们也可以控制它的效果,用:

android:background=”?android:attr/selectableItemBackground” - 设置控件背景颜色透明且波纹有边界
android:background=”?android:attr/selectableItemBackgroundBorderless” - 设置控件背景颜色透明且波纹无边界,将会显示一个圆,直径为控件的长度

我把三个按钮分别不加这个属性,加selectableItemBackground属性,加selectableItemBackgroundBorderless属性,看看效果:

<Button
        android:layout_width="wrap_content"
        android:layout_height="80dp"
        android:text="Button" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="80dp"
        android:background="?attr/selectableItemBackground"
        android:text="Button" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="80dp"
        android:background="?attr/selectableItemBackgroundBorderless"
        android:text="Button" />

效果:
这里写图片描述
可以看到加了这个属性的背景都透明了,无边界时候显示触摸反馈的是一个圆形
当然,我们可以通过设置style文件来设置Button的默认颜色和触摸水波纹颜色:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorControlHighlight">#673AB7</item>
        <item name="colorButtonNormal">#CDDC39</item>
</style>
//或
<style name="AppTheme" parent="android:Theme.Material.Light">
        <item name="android:colorControlHighlight">#673AB7</item>
        <item name="android:colorButtonNormal">#CDDC39</item>
</style>

这两种都可以,因为Theme.AppCompat是Material Design的兼容包,一般在像5.0以下兼容Material Desing风格时候都是使用它,不过使用了它Activity需要继承AppCompatActivity来达到Material design的效果,而且二者不能同时使用,比如不能使用了Theme.Material.Light的主题再让Activity继承AppCompatActivity,否则将报错。具体Material Design如何向下兼容请看我的这篇文章使用Material Design应用主题

揭露效果

关于这个动画,现在比较流行的就是Activity的揭露出现效果,就是打开一个新的Activity或者UI时,Activity界面会从点击的那个点以波纹形式扩散而成,效果比较炫酷,其实就是用这个揭露动画做的,好了,让我们来看看怎么实现这个动画吧,其实就是通过ViewAnimationUtils工具类创建一个圆形的揭露动画对象,然后设置Animator对象的一些属性值。

Animator mAnimator = ViewAnimationUtils.createCircularReveal(View view,
            int centerX,  int centerY, float startRadius, float endRadius)

view - 需要显示揭露动画的View
centerX - 动画开始的X轴坐标
centerY - 动画开始的Y轴坐标
startRadius - 动画开始时的半径
endRadius - 动画结束时的半径

我们知道了以上的参数意思那么接下来可以设置下看看效果:
布局文件中有两个Button:

<Button
        android:id="@+id/button4"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:text="New Button" />

    <Button
        android:id="@+id/button5"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:text="Button" />

分别对这两个Button设置监听器,当点击时候显示动画:

mButton4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Animator mAnimator = ViewAnimationUtils.createCircularReveal(mButton4, mButton4.getWidth()/2, mButton4.getHeight()/2, 0, mButton4.getHeight());
                mAnimator.setDuration(2000);
                mAnimator.setInterpolator(new AccelerateInterpolator());
                mAnimator.start();
            }
        });
        mButton5.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                float endRadius = (float) Math.hypot(mButton5.getWidth(),mButton5.getHeight());//勾股定理得到斜边长度
                Animator mAnimator = ViewAnimationUtils.createCircularReveal(mButton5, mButton5.getWidth(), 0, 0, endRadius);
                mAnimator.setDuration(2000);
                mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
                mAnimator.start();
            }
        });

来看看效果:
这里写图片描述

如上,效果是慢慢的揭露出来的,这个效果用在一些视图显示的场合、或者视图消失的场合比较酷吧,而且揭露动画也是可以设置插值器和一些其它属性的。

转换效果

转换动画主要就是通过ActivityOptions这个类实现的,只支持api21以上的版本,不过这个类只支持Api21以上的版本,好在Google也在v4包中添加了一个向下兼容类:ActivityOptionsCompat,使用它可以在api21以下的系统上运行,但是没有动画效果,在api21以上的系统上运行就有动画效果,这个兼容类可以帮助我们省去了对系统版本的判断,所以我用它来讲解转换动画

转换动画其实可以分为两类:共享元素转换和普通转换。

要使用转换动画,我们首先需要设置这个Activity让它允许使用转换动画,通过getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);表示允许使用转换动画,设置方式有两种,可以在Activity中用代码设置:

protected void onCreate(Bundle savedInstanceState) {
        getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.laytout_image);
    }

也可以在style.xml中设置:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="android:windowContentTransitions">true</item>
</style>

共享元素转换动画

共享元素转换,顾名思义:就是可以把两个Activity中相同元素联系起来作出变换的动画,使用它的前提就是两个Activity有相同的元素,何为元素,即有相同的图片、文本内容、视图等都是元素。那么怎么用呢?

就是通过ActivityOptions创建一个场景转换动画,然后把这个动画传入startActivity()中:

/**
*@activity - 当前的activity
*@sharedElement - 共享的元素视图
*@sharedElementName - 共享元素的名称
*/
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(Activity activity,
            View sharedElement, String sharedElementName)
startActivity(intent, options.toBundle());

这里需要我们传入三个参数,第一个就不说了,第二个就是共享的元素视图,第三个是共享元素的名称,那么怎么获取这两个参数呢?
假如这个界面上有一个ImageView,而另外一个界面上也有一个ImageView,而且这两个ImageView控件的图片都一样,这时候我们可以给这两个ImageView控件的android:transitionName=""(共享元素名称)设置一个相同的名称,名称任意取,所以ImageView就是共享元素了,那么上面的第二个参数当然是传入ImageView了,第三个参数则是传入ImageView的共享元素名称。

所以,我们来实现一个看看:
Activity1:

<ImageView
        android:id="@+id/imageView"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:scaleType="centerCrop"
        android:src="@mipmap/two"
        android:transitionName="sunzxyong" />

Activity2:

 <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:scaleType="centerCrop"
        android:src="@mipmap/two"
        android:transitionName="sunzxyong" />

设置好了布局后,然后跳转界面那里的代码:

ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(this, mImageView, "sunzxyong");
        Intent intent = new Intent(this, ImageDetailActivity.class);
        startActivity(intent, options.toBundle());

运行一下看看效果:
这里写图片描述
这里写图片描述
这样,就实现共享元素动画了,可以看到Activity在切换到第二个界面时是用共享元素来做一些平滑动画效果,在第二个界面返回时候共享元素做一些平滑动画效果返回到第一个界面中,【注意】:当第二个Activity结束时并回退这个动画需要调用finishAfterTransition();而不是finish(),所以在第二个Activity中退出时或返回时(onBackPressed)加入finishAfterTransition();即可,表示当前Activity结束前需要做完这个动画。

如何共享多个元素?假如这两个界面上有多个元素一样,那么共享多个元素可以使用Pair.create()的方法,ActivityOptionsCompat.makeSceneTransitionAnimation还有一个重载方法,为:

/**
*@sharedElements - 可变参数,View表示共享元素视图,String表示共享元素名称
*/
ActivityOptionsCompat.makeSceneTransitionAnimation(Activity activity,
            Pair<View, String>... sharedElements)

所以多个共享元素可以这个写:

ActivityOptionsCompat.makeSceneTransitionAnimation(this,Pair.create((View)mImageView, "sunzxyong"), Pair.create((View)mImageView2, "sunzxyong2"));

ActivityOptionsCompat.makeScaleUpAnimation扩张动画

这个动画也是ActivityOptionsCompat类的一个动画效果,它可以指定一个坐标点,然后显示界面时Activity是从这个坐标点往外扩展的,所以在这里顺便讲一下,先来看看它的参数意思:

/**
*@source - The View that the new activity is animating from,界面是从哪个视图上开始扩张
*@startX - 开始扩张的x坐标
*@startY - 开始扩张的y坐标
*@startWidth - 扩张完后Activity的宽度(为0表示全屏)
*@startHeight - 扩张完后Activity的高度(为0表示全屏)
*/
ActivityOptionsCompat makeScaleUpAnimation(View source,
            int startX, int startY, int startWidth, int startHeight)

我们根据上述定义这样一个动画,让Activity从图片的中心点开始扩张至全屏,如:

ActivityOptionsCompat options = ActivityOptionsCompat.makeScaleUpAnimation(mImageView,mImageView.getWidth()/2,mImageView.getHeight()/2,0,0);
        Intent intent = new Intent(this, ImageDetailActivity.class);
        startActivity(intent, options.toBundle());

效果为:
这里写图片描述
可以看见新的Activity是从图片中心扩张而成的

普通转换效果

普通转换效果有三种:

  • Slide - 滑动效果(默认是从底部往上滑入)
  • Explode - 展开效果
  • Fade - 渐显渐隐效果

它是通过Window.setEnterTransition()和Window.setExitTransition()来控制Activity的进入和退出的转换动画的,所以,使用它我们需要通过getWindow().setEnterTransition(Transition transition);设置,该参数传入的是一个Transition对象,默认的有Slide、Explode和Fade这三种效果,所以,一个标准的设置普通转换效果的代码为:
1、首先要设置该Activity允许使用转换动画
2、然后设置Activity进入和退出的转换动画
3、最后跳转界面时用默认的转换动画ActivityOptionsCompat.makeSceneTransitionAnimation(this);跳转界面,【注】:在有元素共享动画时需要传入其它共享参数,否则,则为普通的转换动画效果

标准的使用代码为:

 protected void onCreate(Bundle savedInstanceState) {
        getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.laytout_image);
        getWindow().setEnterTransition(new Slide());
        getWindow().setExitTransition(new Slide());
        //...
    }
    public void click(View view) {
        ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(this);
        Intent intent = new Intent(this, ***.class);
        startActivity(intent,options.toBundle());
    }

上面在使用getWindow().setEnterTransition(new Slide());传入的是一个Slide对象,其实可以通过它来设置其它的一些参数,比如改变滑入的方向和添加插值器:

Slide mSlide = new Slide();
mSlide.setInterpolator(new AccelerateInterpolator());
mSlide.setSlideEdge(Gravity.TOP);
getWindow().setEnterTransition(mSlide);

其它一些动画效果也是如此设置。
下面通过一个实例来看看具体对应的动画效果是怎么实现的。
先来看看慢动画效果,为了使效果更加明显,我这里设置了动画持续时间为2s,如:
这里写图片描述
再来看看没有时间delay的默认效果:
这里写图片描述
贴下主要代码吧!
跳转界面代码:

public void onItemClick(View view, int position) {
        switch (position) {
            case 2:
                Slide mSlide = new Slide();
                mSlide.setDuration(2000);

                getWindow().setExitTransition(mSlide);
                getWindow().setEnterTransition(mSlide);

                ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(RecyclerViewActivity.this);
                Intent intent = new Intent(RecyclerViewActivity.this, SlideActivity.class);
                startActivity(intent, optionsCompat.toBundle());
                break;
            case 3:
                Explode mExplode = new Explode();
                mExplode.setDuration(2000);

                getWindow().setExitTransition(mExplode);
                getWindow().setEnterTransition(mExplode);

                ActivityOptionsCompat optionsCompat2 = ActivityOptionsCompat.makeSceneTransitionAnimation(RecyclerViewActivity.this);
                Intent intent2 = new Intent(RecyclerViewActivity.this, ExplodeActivity.class);
                startActivity(intent2, optionsCompat2.toBundle());
                break;
            case 4:
                Fade mFade = new Fade();
                mFade.setDuration(2000);

                getWindow().setExitTransition(mFade);
                getWindow().setEnterTransition(mFade);

                ActivityOptionsCompat optionsCompat3 = ActivityOptionsCompat.makeSceneTransitionAnimation(RecyclerViewActivity.this);
                Intent intent3 = new Intent(RecyclerViewActivity.this, FadeActivity.class);
                startActivity(intent3, optionsCompat3.toBundle());
                break;
        }
    }

每个动画跳转至的界面,这里我贴一个,其它都是类似:

protected void onCreate(Bundle savedInstanceState) {
        getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fade);
        Fade mFade = new Fade();
        mFade.setDuration(2000);
        getWindow().setExitTransition(mFade);
        getWindow().setEnterTransition(mFade);

        TextView mTextView = (TextView) findViewById(R.id.textView);
        mTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finishAfterTransition();
            }
        });
    }

当然这三种动画还可以设置插值器和Mode(mSlide.setMode()),从而达到不同效果的实现。
【总结】:综上所述, 使用转换动画时候最主要是先让这个Activity得到使用转换动画的权利,然后再用ActivityOptionsCompat.makeSceneTransitionAnimation(...)得到ActivityOptionsCompat对象并设置给startActivity(),这样就实现了转换动画。

【注】Material Design的动画只适用与5.0以上的版本才有效果

Demo下载

下一篇讲解剩余的三种类型动画。

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值