Material-Animations-master 学习笔记#
好久都有更新博客了,从入安卓开始,学习,上班,最近跳槽了,去了新东家那,离自己的心中的工作又进了一步,新单位同事,领导都挺好,可惜,事业上刚有起色,感情上却受到打击,哎,写一篇博客安慰一下自己吧。
最近公司没有新的业务,自己也抽空学习一些新东西,比如5.0新出的TransitionAnimation,虽然之前也接触过,想学,不过一直没有时间,最近学着都敲了一遍,感觉蛮不错的,参考的项目就是Material-Animations-master,一个特别棒的介绍过渡动画和Transition的项目。
先总体介绍下,总体分四部分,简单的过渡动画,分享元素的过渡动画,通过Transition实现的view动画,ReveaAimation四种,接下来都以此介绍一下。
简单过渡动画
简单的过渡动画分三种吧,Slide,Fade,Explode,滑动,渐变,爆炸三种,基本的使用方法
Slide slideTransition=new Slide();
slideTransition.setSlideEdge(Gravity.LEFT);
slideTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long));
getWindow().setReenterTransition(slideTransition);
getWindow().setExitTransition(slideTransition);
简单的就是new一个Transition对象,做一些基本设置就可以了,动画有了,接下来就是要设置到指定的位置。
getWindow().setEnterTransition(slideTransition);//设置进入动画
getWindow().setExitTransition(slideTransition);//设置退出动画
getWindow().setReturnTransition(slideTransition);//设置返回的动画(这个没具体试过)
getWindow().setReenterTransition(slideTransition);//设置重新进入的动画
简单的过渡动画就这么简单,接下来就是使用startActivity就可以了,在项目中使用了一下别的东西,比如DataBindig,还有RecyclerView,首页面的跳转是通过SamplesRecyclerAdapter里面统一处理的,封装了两个方法用于跳转的不同情况。在Transition中还有一种就是使用XML去编写Transaction,简单的操作跟属性动画并无区别,新建一个transition文件夹,在里面创建文件就可以了, 并不困难,同样的在使用时候使用TransitonSet进行控制,也有interpolator等属性。
transition= TransitionInflater.from(this).inflateTransition(R.transition.explode);
简单的inflate操作,不难理解。
分享元素动画
分享元素作为一种非常有视觉层次感的过渡效果,是值得去追求和学习的。
先说首页跳转到shareFragment的分享元素吧,在adapter中设置的点击时间具体代码
private void transitionToActivity(Class target,SampleViewHolder holder,Sample sample){
final Pair[] pairs=TransitionHelper.
createSafeTransitionParticipants(activity,false,
new Pair<>(holder.binding.sampleIcon,activity.getString(R.string.square_blue_name)),
new Pair<>(holder.binding.sampleName,activity.getString(R.string.sample_blue_title)));
startActivity(target,pairs,sample);
}
可以看到在使用的过程中出现了一个新的类 Pair,简单来说就是一个容器类,跟Map,Set之类的差不多,不过在这里使用的是View和String。用来标记被共享的元素和共享元素的name。在首页的使用过程中是在Adapter中的,所以这种方式可以使用在一些列表或者图片列表效果中,效果会很棒,通过TransitionHelper.createSafeTransitionParticipants方法创建一个Pair对象数组,包含这目标Activity,是否包含目标statusBar,以及两个包含着View与String对应的Pair对象。
接下来通过
private void startActivity(Class target, Pair[] pairs, Sample sample) {
Intent i=new Intent(activity,target);
ActivityOptionsCompat transitionActivityOptions=ActivityOptionsCompat.
makeSceneTransitionAnimation(activity,pairs);
i.putExtra("sample",sample);
activity.startActivity(i,transitionActivityOptions.toBundle());
}
通过ActivityOptionsCompat.makeSceneTransitionAnimation方法来创建一个ActivityOptions对象,其实在5.0之前或者说在没有分享元素,Transition的时候我们也还是可以通过这种方式来控制要启动的actiivty的动画的,使用之前的补间动画就可以。这样一个简单的分享元素动画就实现了, 不过在项目中,我们可以发现,其实在shareFragment中并不是一个简单的Activity,而是包含着两个Fragment的Activity主体内容并没有在activity中,而且值得注意的是,在共享的两个View 中其中一个是在Activity中另一个则是在包含的Fragment中,而在这个Fragment中没有做一些过多的操作,仅仅是设置了一下过度元素效果,5.0中包含以下效果:
- changeBounds 改变目标视图的布局边界
- changeClipBounds 裁剪目标视图边界
- changeTransform 改变目标视图的缩放比例和旋转角度
- changeImageTransform 改变目标图片的大小和缩放比例
通过这两点,可以发现,对于共享元素,没有要求指定要在同一个界面中,一个在Activity一个在Fragmen,或者两个都在Fragment中,目测只要能够显示都可以,必要的实在xml文件中要设置制定的属相,transitioonName作为别分享元素的标记,要与之前在pair中包括的View和String相对应。然后介绍下Fragment设置共享元素效果的方法。直接在开启的事务中添加addSharedElement()这个方法,传入View和String,当然还是要保持相同的transitionName。更多的就是有两个方法,用来判断是否可以让两个过渡动画同时进行,感觉还是不同时进行好一点。
View animations
这个讲的不是过渡动画,就是简单的view动画,不过不同我们之前学习的补间或者属性动画,这种动画是通过两个不同的scene来实现的,感觉这个才是Transition 的本质,过渡动画和分享元素是它的延伸。scene这个单词翻译过来是场景,那就叫过场动画吧,以便与过渡动画区分一下,并没有切换Activity或者Fragment只是换了一个场景。在android的发展过程中,随着用户数量的整体系统平台的提升,越来越多或者说更加优良,有视觉冲击的动画被使用, 也出现了很多不同的实现动画的形式,除了我们所熟知的帧动画,属性动画,补间动画,更多的矢量图动画,过场动画将被越来越的使用。
在这个项目中使用过场动画有两处,一种简单的改变位置和大小,另一种是改变场景。分别介绍一下。
位置大小
先上代码,很好理解
TransitionManager.beginDelayedTransition(viewRoot);
LinearLayout.LayoutParams lp= (LinearLayout.LayoutParams) square.getLayoutParams();
if(positionChaged){
lp.gravity= Gravity.CENTER;
}else {
lp.gravity=Gravity.LEFT;
}
positionChaged=!positionChaged;
square.setLayoutParams(lp);
其中viewRoot是视图的布局,square是要改变的view。首先会调用TransitionManager.beginDelayedTransition();方法来确定要施展动画的布局和Transition的类型,只添加view就是使用默认的Transition,之后就是简单的更改布局中的属性或者view自身的属性来实现动画效果。
TransitionManager.beginDelayedTransition(viewRoot);
ViewGroup.LayoutParams params=square.getLayoutParams();
if(sizeChanged){
params.width=saveWidth;
}else{
saveWidth=params.width;
params.width=200;
}
sizeChanged=!sizeChanged;
square.setLayoutParams(params);
更改view大小的代码基本类似,我们可以简单的看一下效果,会发现,这么写其实和写一个属性动画差不多,都是通过改变view自身来改变的,不过对于属性动画来说想要改变位置会主动改变自身的位置,而不是像过场动画一下,去改变父布局的属性,来实现,从这一点来说,过场动画更灵活,也适用更多的场景和复杂的动画,我们继续往下看。
场景变换
作为Transition的基本使用,个人感觉过渡动画并不是Transition的主要功能,简单有效的从一个场景切换到另一个场景,过渡平滑不突兀,这才是Transition应该有的操作。
这AnimationActivity2中有五个Scene,在页面加载的时候就通过TransitionManager.go(scene0);方法来初始化一个场景并添加到Activity中,初始化时通过
scene0=Scene.getSceneForLayout(sceneRoot,R.layout.activity_animations_scene0,this);
scene0.setEnterAction(new Runnable() {
@Override
public void run() {
for(int i=0;i
先通过getSceneForLayout方法来获得一个Scene对象,而且可以给这个场景设置进入和退出的动作,在初始化的时候需要指定要替换的布局。
之后继续初始化其他四个Scene
scene1=Scene.getSceneForLayout(sceneRoot,R.layout.activity_animations_scene1,this);
scene2=Scene.getSceneForLayout(sceneRoot,R.layout.activity_animations_scene2,this);
scene3=Scene.getSceneForLayout(sceneRoot,R.layout.activity_animations_scene3,this);
scene4=Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene4,this);
在场景初始化之后就可以通过java TransitionManager.go(scene1,new ChangeBounds());
方法来更换场景并且可以指定切换场景间的动画。看过项目的人都清楚,如果单纯的让我们用属性动画去做的话,那个工作量可不是一般的大。在复杂布局的切换中使用这种改变场景的方式明显的更为方便和便捷。
RevealAnimation
RevealAnimation 中文不准确的翻译:揭露动画(有点不雅)。这个里面涉及的有些多,一步步分开来说。
首先是进入的动画,一个橘黄色的小球的共享元素动画。这动画的过程中,可能是本人个人水平有限,仔细观察后发现其实移动的路径是曲线而且退出和进入时的路径是不同的,而且在代码中并没有指定移动的路径,猜测是共享元素过程中默认设置的。有待研究。接下来就按照颜色去分析。
绿色
在点击绿色按钮之后会从布局的中间偏下的位置开始一个Reveal动画,查看调用的方法我们可以找个这个:
/**
*创建Reveal动画并执行
*
* @param viewRoot 要执行动画的布局
* @param color 揭露的颜色
* @param cx 揭露点的X坐标
* @param cy 揭露点的Y坐标
* @return 返回创建成功的动画
*/
private Animator animateRevealColorFromCoordinates(ViewGroup viewRoot, int color, int cx, int cy) {
float finalRadius= (float) Math.hypot(viewRoot.getWidth(),viewRoot.getHeight());
Animator anim=ViewAnimationUtils.createCircularReveal(viewRoot,cx,cy,0,finalRadius);
viewRoot.setBackgroundColor(ContextCompat.getColor(this,color));
anim.setDuration(getResources().getInteger(R.integer.anim_duration_long));
anim.setInterpolator(new AccelerateDecelerateInterpolator());
anim.start();
return anim;
}
首先通过math.hypot一个没有见过的数学方法来求出要执行的最终的半径,hypot方法的意思是求两个数平方和的平方根,白话的意思就是求直角三角形斜边长。用在这里的意思就是求布局对角线的长度。之后通过ViewAnimationUtils.createCircularReveal()方法创建一个RevealAnimator,需要的参数有布局,坐标点,起始半径和最终半径。设置时间和差值器之后就可以运行了,使用并不难。
红色
点击红色按钮与点击绿色按钮的动画有两点不同,一是会有一个红球的位移,二是在红球右侧的蓝球和橘黄色球会往右有一个简单的位移和缩小,至于揭露动画的部分其实就是一个颜色的改变。
final ViewGroup.LayoutParams originalParams = btnRed.getLayoutParams();
Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.changebounds_with_arcmotion);
transition.addListener(new Transition.TransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
}
@Override
public void onTransitionEnd(Transition transition) {
animateRevealColor(bgViewGroup, R.color.sample_red);
body.setText(R.string.reveal_body3);
body.setTextColor(ContextCompat.getColor(RevealActivity.this, R.color.theme_red_background));
btnRed.setLayoutParams(originalParams);
}
@Override
public void onTransitionCancel(Transition transition) {
}
@Override
public void onTransitionPause(Transition transition) {
}
@Override
public void onTransitionResume(Transition transition) {
}
});
TransitionManager.beginDelayedTransition(bgViewGroup, transition);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
btnRed.setLayoutParams(layoutParams);
简单看来就是先获得当前的布局状态,之后开启一个之前用过的Transition,设置新的布局属性,这个主要是用来实现红球从底部移动到屏幕中部,之后开启一个揭露动画,之前介绍过就不多赘述了,比较奇怪的是在代码中并没有看到关于在红球移动过程中对其他几个球的动画代码,从这一点上来看,过场动画的强大,会默认的帮我们实现一些符合现实情景的动作。
剩下的蓝球和黄球其实就是改变揭露动画的起始位置,其他的并没有太大的变化,就说到这。
总结
关于动画的东西其实我写了很多,主要是个人比较喜欢这种东西,从最基础的帧动画,补间动画,再到属性动画,多种不同方式去实现属性动画,再到5.0的过渡动画和过场动画,分享元素,更多的还有SVG矢量图动画等等,随着Android系统的发展,有越来越多的形式能够使我们的APP变得更加贴近生活,更能吸引人。我们也要不断的学习心的东西,才不会被时代淘汰掉。
以后可能会换个地方写文章,争取每周一篇,可以的话也会弄一个个人的博客,文章也会同步更新到。