MD动画是谷歌推出的一种动画效果,其实现的效果能让用户看着很是舒服,符合MD动画的动画,有很强的用户交互体验
Touch Feedback(触摸反馈)
在触摸反馈这一块,用的最多的就是水波纹效果,而水波纹效果是从5.0才开始出现的,从5.0开始,便已自带水波纹效果
以下是一个水波纹的按钮示例
<?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:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="自带效果" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:text="系统效果 有边界" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:text="系统效果 无边界" />
</LinearLayout>
其效果如下
可以明显看出,不使用系统属性的button自带水波纹效果,这主要是由于使用了AppCompat的主题的原因,当然,也可以在主题中修改背景和水波纹的颜色
<item name="colorControlHighlight">?attr/colorPrimary</item>
<item name="colorControlNormal">@android:color/holo_orange_light</item>
在使用AppCompat主题的时候,Activity最好也使用AppCompatActivity,可以实现更好的兼容
上面的例子可以看出selectableItemBackground
是不带按钮边界的,但在点击时候会后水波纹,长按时会显示出轮廓,selectableItemBackgroundBorderless
也没有轮廓,长按时会显示出圆形,圆的大小与控件的宽高最大值匹配
Reveal Effect(揭露效果)
比如Activity的揭露出现的效果,需要使用ViewAnimationUtil工具类来设置View
比如要实现一个水波纹揭露效果,那么需要操作的View,扩散的中心点,开始的扩散半径,结束的扩散半径,函数原型如下
ViewAnimationUtils.createCircularReveal(view, centerX, centerY, startRadius, endRadius)
这里扩散一个按钮作为示例
布局就只有一个按钮
<?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">
<Button
android:id="@+id/button"
android:onClick="revealAnimation"
android:layout_width="100dp"
android:layout_height="100dp" />
</LinearLayout>
然后实现其效果
public void revealAnimation(View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Animator animator = ViewAnimationUtils.createCircularReveal(view, view.getWidth() / 2,
view.getHeight() / 2, 0,
(float) Math.hypot(view.getWidth(), view.getHeight()));
animator.setDuration(1000);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
}
}
实现效果如下图
Activity transition(Activity转场动画效果)
要实现转场动画就需要使用到ActivityOptions,而这个类只支持5.0及以上版本,在v4包中有一个ActivityOptionsCompat,其作用一致,但在低于5.0的版本中,却无法实现转场动画,只是避免了在使用ActivityOptions时候的版本判断
不使用MD的转场动画例子
startActivity(new Intent(this, SecondActivity.class));
overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
MD转场动画主要分为两大类:共享元素转换和普通转换
转场动画使用前提
要使用转场动画,就需要设置转场动画使用允许,例如A,B两个活动,从A到B的转场动画依赖于两个活动允许转场动画
设置转场动画方式:代码方式和主题方式,两种方法都可以实现
代码方式,这个是设置在setContentView()
之前
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
主题方式
<item name="android:windowContentTransitions">true</item>
这里使用第一种,因为这样方便控制
共享元素转换
在不使用转场动画的时候,activity跳转默认效果如下
可以把两个Activity当中的相同的元素关联起来做连贯的变换动画
要实现共享元素的转换,就需要设置共享元素的元素名 使用android:transitionName
属性设置其view名,两个元素名相同就可实现共享元素转换
这里实现了两个Activity,并且已经注册
FirstActivity布局及活动
<?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">
<ImageView
android:id="@+id/first_image_view"
android:layout_width="200dp"
android:layout_height="300dp"
android:src="@drawable/image"
android:transitionName="iamge"
android:scaleType="centerCrop"
android:onClick="startSecondActivity"/>
</LinearLayout>
public class First_Activity extends AppCompatActivity {
private ImageView imageView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
setContentView(R.layout.activity_first);
imageView = findViewById(R.id.first_image_view);
}
public void startSecondActivity(View view) {
ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(
this, imageView, "image");
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent, optionsCompat.toBundle());
}
}
SecondActivity布局及活动
<?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">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/image"
android:transitionName="iamge" />
</LinearLayout>
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
setContentView(R.layout.activity_second);
}
}
实现效果图如下
按返回键的时候自动实现了返回的共享元素转场动画,这是在源代码中实现的
单个元素共享
ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(this, imageView, "image");
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent, optionsCompat.toBundle());
多个元素共享
要使元素关联起来,例如FirstActivity中有ImageView和Button,分别设置为image,button,那么在SecondActivity中也要相应设置image和button
ActivityOptionsCompat optionsCompat = ActivityOptionsCompat
.makeSceneTransitionAnimation(this, Pair.create((View)imageView, "image"),Pair.create((View)button, "button"));
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent, optionsCompat.toBundle());
普通转场动画
普通转场动画主要有三种效果:滑动效果(Slide)、展开效果(Explode)、渐变显示隐藏效果(Fade)
这里使用一个跳转界面,复用跳转后的界面,实现转场动画,同时返回时候动画也与跳转动画相统一
跳转界面
public class NormalActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_normal);
}
public void startSlide(View view) {
Slide slide = new Slide();
slide.setDuration(3000);
getWindow().setExitTransition(slide);
getWindow().setEnterTransition(slide);
ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(this);
Intent intent = new Intent(this, NormalAnimActivity.class);
intent.setType("slide");
startActivity(intent, optionsCompat.toBundle());
}
public void startExplode(View view) {
Explode explode = new Explode();
explode.setDuration(3000);
getWindow().setExitTransition(explode);
getWindow().setEnterTransition(explode);
ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(this);
Intent intent = new Intent(this, NormalAnimActivity.class);
intent.setType("explode");
startActivity(intent, optionsCompat.toBundle());
}
public void startFade(View view) {
Fade fade = new Fade();
fade.setDuration(3000);
getWindow().setExitTransition(fade);
getWindow().setEnterTransition(fade);
ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(this);
Intent intent = new Intent(this, NormalAnimActivity.class);
intent.setType("fade");
startActivity(intent, optionsCompat.toBundle());
}
}
跳转界面布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/first_image_view"
android:layout_width="200dp"
android:layout_height="300dp"
android:scaleType="centerCrop"
android:src="@drawable/image" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Slide"
android:onClick="startSlide"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Explode"
android:onClick="startExplode"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Fade"
android:onClick="startFade"/>
</LinearLayout>
</RelativeLayout>
展示界面
public class NormalAnimActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_normal_anim);
String type = getIntent().getType();
switch (type){
case "slide":
Slide slide = new Slide();
slide.setDuration(3000);
getWindow().setExitTransition(slide);
getWindow().setEnterTransition(slide);
break;
case "explode":
Explode explode = new Explode();
explode.setDuration(3000);
getWindow().setExitTransition(explode);
getWindow().setEnterTransition(explode);
break;
case "fade":
Fade fade = new Fade();
fade.setDuration(3000);
getWindow().setExitTransition(fade);
getWindow().setEnterTransition(fade);
break;
}
}
}
展示界面布局
<?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">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/image" />
</LinearLayout>
为了更好的看见过程,这里设置的的动画时间有点长,设置为3秒
实现效果如下,图片有点大
如果有共享元素,可以设置共享元素,那么它就会按照共享元素动画执行,其他的子view就会按照Fade动画执行