Material Design当中的动画(一)

参考:https://developer.android.google.cn/reference/android/graphics/drawable/RippleDrawable.html
https://developer.android.google.cn/training/material/animations.html#Reveal

在material主题当中为按钮和activity transition提供了很多默认的动画,并且在API21及以上允许我们自定义这些动画,包括以下几个部分:
1、触摸反馈动画
2、循环揭露动画
3、Activity transitions动画
4、曲线运动
5、视图状态改变
接下来对这些效果一一进行讲解:

1、触摸反馈

触摸反馈就是我们和UI进行交互的时候呈现出来的动画效果,最典型的就是我们点击按钮的时候呈现出来的水波纹动画效果。
实现这个效果最简单的方式就是设置View的背景为:
?android:attr/selectableItemBackground,这个代表有界的波纹
?android:attr/selectableItemBackgroundBorderless 这个代表无界的波纹,这个波纹将会扩展到其父类
注意:selectableItemBackgroundBorderless是API21中新加的attribute
以上两种波纹效果的波纹颜色是固定的,那么要想改变波纹的颜色,就得使用RippleDrawable这个类了,可以在xml文件当中定义RippleDrawable。
通过类的层次结构可以发现RippleDrawable是继承自LayerDrawable的。

在xml当中定义RippleDrawable:

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

还可以不定义mask层,这样就会出现背景,这个背景的drawable还可以是别的drawable:

<?xml version="1.0" encoding="utf-8"?>
  <ripple xmlns:android="http://schemas.android.com/apk/res/android"
      android:color="#ffff0000" >
    <item android:drawable="@android:color/darker_gray"/>
  <!--
<item android:drawable="@drawable/icon"/>
-->
  </ripple>

还可以既不定义mask又不定义子层,此时的波纹效果将会超出View的边界:

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

我们只需要设置在xml文件当中设置View的backgroud为以上定义的 RippleDrawable即可。
下面来看下效果,首先是布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/content_material_design_animatio"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.easyliu.test.animationdemo.MaterialDesignAnimation.MaterialDesignAnimatioActivity"
    tools:showIn="@layout/activity_material_design_animatio"
    >
  <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="center_horizontal"
      android:layout_marginTop="10dp"
      android:background="?android:attr/selectableItemBackground"
      android:clickable="true"
      android:text="textview bounded ripple"
      android:textSize="20sp"
      />
  <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="center_horizontal"
      android:layout_marginTop="10dp"
      android:background="?android:attr/selectableItemBackgroundBorderless"
      android:clickable="true"
      android:text="textview Borderless ripple"
      android:textSize="20sp"
      />
  <Button
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="center_horizontal"
      android:layout_marginTop="10dp"
      android:background="@drawable/ripple_drawable_normal"
      android:text="Customize Touch Feedback normal"
      android:textSize="20sp"
      />

  <Button
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="center_horizontal"
      android:layout_marginTop="10dp"
      android:background="@drawable/ripple_drawable_no_mask"
      android:text="Customize Touch Feedback no mask"
      android:textSize="20sp"
      />
  <Button
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="center_horizontal"
      android:layout_marginTop="10dp"
      android:background="@drawable/ripple_drawable_no_mask_and_childlayer"
      android:text="Customize Touch Feedback no mask and childlayer"
      android:textSize="20sp"
      />
</LinearLayout>

效果如下:
这里写图片描述

2、循环揭露动画

当隐藏或者显示View的时候,揭露动画提供用户一种视觉的连续性,使用方式如下所示,主要是使用ViewAnimationUtils.createCircularReveal() 方法。不过这里需要注意:确保getWidth()以及getHeight()能够获取到有效的值,不然没有动画效果。

private void initView() {
  final View revealView = findViewById(R.id.btn_reveal);
  findViewById(R.id.btn_toggle_view).setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View view) {
      if (revealView.getVisibility() == View.VISIBLE) {
        // get the center for the clipping circle
        int cx = revealView.getWidth() / 2;
        int cy = revealView.getHeight() / 2;
        // get the final radius for the clipping circle
        float initialRadius= (float) Math.hypot(cx, cy);
        // create the animation (the final radius is zero)
        Animator anim =
            ViewAnimationUtils.createCircularReveal(revealView, cx, cy, initialRadius, 0);
        anim.setDuration(1000);
        anim.setInterpolator(new AccelerateDecelerateInterpolator());
        // make the view invisible when the animation is done
        anim.addListener(new AnimatorListenerAdapter() {
          @Override public void onAnimationEnd(Animator animation) {
            super.onAnimationEnd(animation);
            revealView.setVisibility(View.INVISIBLE);
          }
        });
        anim.start();
      } else {
        // get the center for the clipping circle
        int cx = revealView.getWidth() / 2;
        int cy = revealView.getHeight() / 2;
        // get the final radius for the clipping circle
        float finalRadius= (float) Math.hypot(cx, cy);
        // create the animator for this view (the start radius is zero)
        Animator anim =
            ViewAnimationUtils.createCircularReveal(revealView, cx, cy, 0, finalRadius);
        anim.setDuration(1000);
        anim.setInterpolator(new AccelerateDecelerateInterpolator());
        // make the view visible and start the animation
        revealView.setVisibility(View.VISIBLE);
        anim.start();
      }
    }
  });
}

效果如下:
这里写图片描述

3、Activity Transition

material design当中可以为activity指定enter和exit动画以及activity之间共享元素的动画。
enter动画代表activity当中的view怎么进入界面
exit动画代表activity当中的view怎么退出界面
shared elements动画代表两个activity之间共享的view表现的动画,比如两个activity有相同的图片,只是位置和大小不相同,此时就可以把这张图片指定为共享元素,为其指定动画。

Android5.0支持以下的enter和exit动画:
explode:view从界面的中心进入或退出
slide:view从界面的边缘进入或退出
fade:view通过改变自身的大小来进入或退出

Android5.0支持以下的shared elements动画:
changeBounds - Animates the changes in layout bounds of target views.
changeClipBounds - Animates the changes in clip bounds of target views.
changeTransform - Animates the changes in scale and rotation of target views.
changeImageTransform - Animates changes in size and scale of target images.
如下所示即为拥有共享元素的activity之间的transition
这里写图片描述

为activity指定transition的步骤:
1、设置activity的主题,包括enter和exit的activity都得设置主题,如下所示。
首先需要 enable window content transitions,也就是设置name=“android:windowActivityTransitions”为true
然后就是设置enter和exit动画,最后设置共享元素动画,如ActivityTransitionTheme所示。

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
  <!-- Customize your theme here. -->
  <item name="colorPrimary">@color/colorPrimary</item>
  <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
  <item name="colorAccent">@color/colorAccent</item>
</style>

<style name="AppTheme.NoActionBar">
  <item name="windowActionBar">false</item>
  <item name="windowNoTitle">true</item>
</style>

<style name="ActivityTransitionTheme" parent="AppTheme.NoActionBar">
  <!-- enable window content transitions -->
  <item name="android:windowActivityTransitions">true</item>

  <!-- specify enter and exit transitions -->
  <item name="android:windowEnterTransition">@transition/explode</item>
  <item name="android:windowExitTransition">@transition/explode</item>

  <!-- specify shared element transitions -->
  <item name="android:windowSharedElementEnterTransition">@transition/move_image
  </item>
  <item name="android:windowSharedElementExitTransition">@transition/move_image
  </item>
  <item name="android:windowAllowReturnTransitionOverlap">true</item>
  <item name="android:windowAllowEnterTransitionOverlap">false</item>
</style>

需要在res目录下新建transition目录,然后定义explode.xml以及move_image.xml这两种动画效果:
explode.xml:

<?xml version="1.0" encoding="utf-8"?>
<explode/>

move_image.xml:

<?xml version="1.0" encoding="utf-8"?>
<transitionSet>
  <changeBounds/>
  <changeImageTransform/>
</transitionSet>

当然也可以在代码中设置这些动画,如果不在主题中指定的话。
// inside your activity (if you did not enable transitions in your theme)
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);

// set an exit transition
getWindow().setExitTransition(new Explode());

主要有以下几个函数:
Window.setEnterTransition()
Window.setExitTransition()
Window.setSharedElementEnterTransition()
Window.setSharedElementExitTransition()
Window.setAllowEnterTransitionOverlap()
2、接下来就是执行activity的跳转了:

Intent intent = new Intent(TransitionExitActivity.this, TransitionEnterActivity.class);
startActivity(intent,
    ActivityOptions.makeSceneTransitionAnimation(TransitionExitActivity.this).toBundle());

在进入的activity当中,当点击按钮finish自己返回的时候,为了呈现相同的动画效果,需要调用finishAfterTransition()而不是finish()函数。
最终效果如下所示:
这里写图片描述

4、共享元素的ActivityTransition

以上只是简单的activity transition,并没有使用共享元素,接下来讲解具有共享元素的activityTransition,首先看效果。这张图片就是共享元素。
这里写图片描述

实现步骤如下:
1、给共享元素设置android:transitionName 属性,两个Activity当中的ImageView都得设置这个属性,且名字得相同
2、点击ExitActivity当中的imageView执行跳转:

indViewById(R.id.iv_share_element).setOnClickListener(new View.OnClickListener() {
  @Override public void onClick(View view) {
Intent intent = new Intent(TransitionExitActivity.this, TransitionEnterActivity.class);
intent.putExtra(KEY_ID,R.drawable.ball);
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(TransitionExitActivity.this, view,
TRANSITION_NAME).toBundle());
  }
});

需要把imageView和TransitionName都传入,同时把imageView的资源id作为参数传过去,这样接收的Activity就能得到这个资源id,从而设置imageView,如下所示:

int  imageResourceId=getIntent().getIntExtra(KEY_ID,0);
ImageView imageView= (ImageView) findViewById(R.id.iv_share_element);
imageView.setImageResource(imageResourceId);
imageView.setOnClickListener(new View.OnClickListener() {
  @Override public void onClick(View view) {
    finishAfterTransition();
  }
});

通过这种方式就达到了共享元素transition的效果。

代码下载地址:https://github.com/EasyLiu-Ly/AndroidBlogDemo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值