主目录见:Android高级进阶知识(这是总目录索引)
我们都知道,在5.0之后引入了很多新的转场动画,使过渡更加的合理化了,适当地加入动画能使你的app看起来眼前一亮,第一印象取胜,所以我们有理由来学习它,为了有兴趣看下去,我们先亮出效果,录屏有点卡顿,实际比较流畅:
想要代码的可以直接[点击下载],然后适当地在自己app里面放飞吧。
一.目标
今天的目标比较单纯,就是为了给我们的应用程序增加点吸引力,使别人有兴趣玩你的app,所以目标有以下:
1.练习使用共享元素动画和TransitionManager;
2.能在适当的时候使用这些动画。
二.代码分析
Material Design 为场景切换提供了非常优雅的视觉效果,在进入和退出页面,元素共享页面的时候都可以添加想要的效果,而且能让你感觉运动就应该是这样的,这样其实就已经成功了。
1.过渡效果
过渡这个地方我是在例子里面顺便加入的,但是防止有的人这个都没有用过,这里就提一下,过渡的场景如下:
1.首先打开A页面
2.然后A页面跳转到B页面
3.接着回到A页面
首先针对这几个场景我们可以设置的方法有下面几个:
1.android:windowEnterTransition 首次进入显示的动画
2.android:windowExitTransition 启动新 Activity ,此页面退出的动画
3.android:windowReenterTransition 重新进入的动画。即第二次进入,可以和首次进入不一样。
4.android:windowReturnTransition 调用 finishAfterTransition() 退出时,此页面退出的动画
即可以调用getWindow().setReenterTransition(new Explode())等,其他方法类似。传进去的参数是效果,页面切换的动画有以下三个:
1.Explode:从中心移入或移出
2.Slide:从边缘移入或移出
3.Fade:调整透明度产生渐变
这些就是页面切换会设置的动画效果,这些效果还可以设置一些属性:
// 设置动画的时间。类型:long
transition.setDuration();
// 设置修饰动画,定义动画的变化率,具体设置往下翻就看到了
transition.setInterpolator();
// 设置动画开始时间,延迟n毫秒播放。类型:long
transition.setStartDelay();
// 设置动画的运行路径
transition.setPathMotion();
// 改变动画 出现/消失 的模式。Visibility.MODE_IN:进入;Visibility.MODE_OUT:退出。
transition.setMode();
// 设置动画的监听事件
transition.addListener()
好了,借鉴和总结了下这个,我们就进入今天的主题吧
2.共享元素动画
首先我们为了演示这个动画,我们弄了个RecyclerView,然后在点击某个item的时候加入动画,为了使用共享元素动画。
1.我们首先要在setContentView方法前加入:
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
或者你可以直接在style文件中设置如下,然后加入Activity中去:
<item name="android:windowContentTransitions">true</item>
2.然后在要共享运动的地方加上共享元素标识,首先在A页面如下:
然后我们看下要跳转页面B的布局下面添加相同transitionName:
3.现在准备工作做完了,我们现在可以在A页面启动B页面了,代码如下:
mAdapter.setOnItemClickListener(new MyAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Intent intent = new Intent(MainActivity.this,DetailActivity.class);
// startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this,view.findViewById(R.id.ivChallenger),"sharedChallenger").toBundle());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this,
Pair.create(view.findViewById(R.id.ivChallenger),"sharedChallenger"),
Pair.create(view.findViewById(R.id.tvTitle),"sharedTitle"),
Pair.create(view.findViewById(R.id.tvContent),"sharedContent")).toBundle());
}else{
ActivityTransitionLauncher.with(MainActivity.this).from(view.findViewById(R.id.ivChallenger)).launch(intent);
}
}
});
我们看到这段代码里面判断了Android的版本,为了做兼容,我们这里引入了一个兼容库,如果版本低于21的话我们就走兼容库,兼容库地址请点击,效果没有谷歌原生好,但是可以做个替代方案。然后我们看到这里会把想要共享元素的都用Pair设置进去,然后我们调用ActivityOptions的makeSceneTransitionAnimation()方法,最后用toBundle()转化为Bundle对象传给startActivity()方法即可。
4.最后我们在要跳转的页面加入如下的代码:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// getWindow().setEnterTransition(new Slide());//从场景的边缘移入或移出
getWindow().setEnterTransition(new Fade());//调整透明度产生渐变效果
// getWindow().setEnterTransition(new Explode());//从场景的中心移入或移出
ChangeBounds changeBounds = new ChangeBounds();//改变目标视图的布局边界
// ChangeTransform changeTransform = new ChangeTransform();//改变目标视图的缩放比例和旋转角度
// ChangeImageTransform changeImageTransform = new ChangeImageTransform();//改变目标图片的大小和缩放比例
// ChangeClipBounds changeClipBounds = new ChangeClipBounds();//裁剪目标视图边界
// changeBounds.setDuration(1000);
getWindow().setSharedElementEnterTransition(changeBounds);
}else{
ActivityTransition.with(getIntent()).to(findViewById(R.id.ivChallenger))
.duration(300).start(savedInstanceState);
}
同样的我们也加入了版本的判断来做兼容,这里有这么多注释掉的代码是为了大家看到共享元素的动画可以设置的动画效果有这么多。(ChangeBounds,ChangeTransform,ChangeImageTransform,ChangeClipBounds)这些效果已经注释有说明,这里就不贴出来这些效果的演示,大家可以下载我的代码然后打开看看效果。好啦。共享元素使用不是非常难,就是有兼容性问题,不过我们相信不久的将来我们会不需要做兼容了。(这里的setEnterTransition()方法和setSharedElementEnterTransition()方法同样可以在xml中设置)
3.场景切换(TransitionManager)
这个动画也是很酷的,我也是这次弄共享元素动画时候get到的,大家可以看看,还是蛮炫的。首先我们在xml文件布局如下:
<?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">
<FrameLayout
android:id="@+id/flScene"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="400dp">
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btnSwitchScene"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="切换场景"
/>
<Button
android:id="@+id/btnSwitchScene1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="切换场景1"
/>
<Button
android:id="@+id/btnSwitchScene2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="切换场景2"
/>
</LinearLayout>
</LinearLayout>
其中FrameLayout就是到时放我们场景的地方,每个场景对应于一个布局。在代码onCreate里面我们获取每个场景代码如下:
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private void setupLayout(){
scene0 = Scene.getSceneForLayout(flScene,R.layout.detail_activity,this);
scene1 = Scene.getSceneForLayout(flScene,R.layout.detail_activity_scene,this);
scene2 = Scene.getSceneForLayout(flScene,R.layout.detail_activity_scene1,this);
scene3 = Scene.getSceneForLayout(flScene,R.layout.detail_activity_scene2,this);
}
其中第一个参数flScene是对应于容器FrameLayout的,第二个参数是场景的布局,第三个是Context。大家只要对应上去就可以了。我这里还添加了进入的动画:
getWindow().setEnterTransition(new Slide());
getWindow().getEnterTransition().addListener(new Transition.TransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
}
@Override
public void onTransitionEnd(Transition transition) {
TransitionManager.go(scene3);
}
@Override
public void onTransitionCancel(Transition transition) {
}
@Override
public void onTransitionPause(Transition transition) {
}
@Override
public void onTransitionResume(Transition transition) {
}
});
然后我监听了动画的执行过程,在执行完毕的时候进入到场景scene3。然后其他场景就是点击页面中的按钮中进入,分别如下:
1. TransitionManager.go(scene0, new ChangeBounds());
2.//TransitionManager.go(scene1, TransitionInflater.from(TransitionManagerActivity.this)
//.inflateTransition(R.transition.slide_and_changebounds));
TransitionManager.go(scene1,TransitionInflater.from(TransitionManagerActivity.this).
inflateTransition(R.transition.slide_and_changebounds_sequential_with_interpolators));
3. TransitionManager.go(scene2,TransitionInflater.from(TransitionManagerActivity.this)
.inflateTransition(R.transition.slide_and_changebounds_sequential));
其中inflateTransition进来的动画就是跟我们共享元素支持的动画一样,我们看其中一个transition包中slide_and_changebounds_sequential.xml:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/anim_duration_long"
android:transitionOrdering="sequential">
<slide/>
<changeBounds/>
</transitionSet>
我们看到这个就是我们前面支持动画的xml写法而已。
总结:到这里我们要讲的动画已经都讲完成了,动画还得大家下载代码下来看下效果,这样印象比较深刻,希望大家都能做出Awesome Application!!!