您好,欢迎访问一九零五行业门户网

Fab 和 Dialog 之间的过渡效果(Fab and Dialog Morphing Animation)_html/css_WEB-ITnose

最近在读plaid的源码,发现fab和dialog之间切换的动画效果好舒服,于是就研究了下,将其从plaid项目中抽离出来,然后再改进了些代码,更加方便易懂,也更加简单易用。效果如下,项目源码地址
实现原理分析 1.在前面的《android群英传》的读书笔记中提到过activity共享元素过渡动画的实现方式
共享元素过渡动画:一个共享元素过渡动画决定两个activity之间的过渡怎么共享它们的视图,包括了
changebounds:改变目标视图的布局边界;
changeclipbounds:裁剪目标视图的边界;
changetransform:改变目标视图的缩放比例和旋转角度;
changeimagetransform:改变目标图片的大小和缩放比例。
使用方式:假设activity从a跳转到b,那么将a中原来的startactivity改为如下代码:
//单个共享元素的调用方式startactivity(intent,activityoptions.makescenetransitionanimation(this, view, share).tobundle());//多个共享元素的调用方式startactivity(intent,activityoptions.makescenetransitionanimation(this, pair.create(view, share), pair.create(fab, fab)).tobundle());
然后在b的oncreate方法中添加如下代码:
//声明需要开启activity过渡动画getwindow().requestfeature(window.feature_content_transitions);
其次还要在activity a和b的布局文件中为共享元素组件添加android:transitionname=xxx属性。
2.源码中的dialog实际上是activity,并设置了android:windowistranslucent为true,所以从fab到dialog的动画效果实际上是activity的过渡动画。但是,如果单纯的只是使用activity的共享元素过渡动画,将fab作为共享元素的话,效果并不好,不是那么的舒服。
3.为了让过渡效果更加舒服,这里添加了两个渐变效果,一个是color,从fab的颜色到dialog的背景颜色的渐变;另一个是cornerradius,即圆角幅度的渐变。请看下面的代码实现:
/** * morphtransition扩展自changebounds(共享元素的动画的一种),它在原有动画基础上添加了color和cornerradius的动画效果,这个类实际上是整合了morphfabtodialog和morphdialogtofab两个类的作用 * * a transition that morphs a circle into a rectangle, changing it's background color. */public class morphtransition extends changebounds { private static final string property_color = color; private static final string property_corner_radius = cornerradius; private static final string[] transition_properties = { property_color, property_corner_radius }; private int startcolor = color.transparent; private int endcolor = color.transparent; private int startcornerradius = 0; private int endcornerradius = 0; private boolean isshowviewgroup = false; public morphtransition(int startcolor, int endcolor, int startcornerradius, int endcornerradius, boolean isshowviewgroup) { super(); setstartcolor(startcolor); setendcolor(endcolor); setstartcornerradius(startcornerradius); setendcornerradius(endcornerradius); setisshowviewgroup(isshowviewgroup); } public morphtransition(context context, attributeset attrs) { super(context, attrs); } @override public string[] gettransitionproperties() { return transition_properties; } @override public void capturestartvalues(transitionvalues transitionvalues) { super.capturestartvalues(transitionvalues); final view view = transitionvalues.view; if (view.getwidth() <= 0 || view.getheight() <= 0) { return; } transitionvalues.values.put(property_color, startcolor); transitionvalues.values.put(property_corner_radius, startcornerradius);//view.getheight() / 2 } @override public void captureendvalues(transitionvalues transitionvalues) { super.captureendvalues(transitionvalues); final view view = transitionvalues.view; if (view.getwidth() <= 0 || view.getheight() <= 0) { return; } transitionvalues.values.put(property_color, endcolor);//contextcompat.getcolor(view.getcontext(), r.color.dialog_background_color) transitionvalues.values.put(property_corner_radius, endcornerradius); } @override public animator createanimator(final viewgroup sceneroot, transitionvalues startvalues, final transitionvalues endvalues) { animator changebounds = super.createanimator(sceneroot, startvalues, endvalues); if (startvalues == null || endvalues == null || changebounds == null) { return null; } integer startcolor = (integer) startvalues.values.get(property_color); integer startcornerradius = (integer) startvalues.values.get(property_corner_radius); integer endcolor = (integer) endvalues.values.get(property_color); integer endcornerradius = (integer) endvalues.values.get(property_corner_radius); if (startcolor == null || startcornerradius == null || endcolor == null || endcornerradius == null) { return null; } morphdrawable background = new morphdrawable(startcolor, startcornerradius); endvalues.view.setbackground(background); animator color = objectanimator.ofargb(background, background.color, endcolor); animator corners = objectanimator.offloat(background, background.corner_radius, endcornerradius); ////...... animatorset transition = new animatorset(); transition.playtogether(changebounds, corners, color); transition.setduration(300); transition.setinterpolator(animationutils.loadinterpolator(sceneroot.getcontext(), android.r.interpolator.fast_out_slow_in)); return transition; } public void setendcolor(int endcolor) { this.endcolor = endcolor; } public void setendcornerradius(int endcornerradius) { this.endcornerradius = endcornerradius; } public void setstartcolor(int startcolor) { this.startcolor = startcolor; } public void setstartcornerradius(int startcornerradius) { this.startcornerradius = startcornerradius; } public void setisshowviewgroup(boolean isshowviewgroup) { this.isshowviewgroup = isshowviewgroup; }}
4.上面的代码中用到了morphdrawable类,它继承自drawable,并添加了前面提到的那两个属性以用于产生属性动画,默认是没有为那两个属性添加set/get方法的,所以需要进行扩展。关于属性动画可以看以前的读书笔记,重要代码如下:
/** * 形态和颜色可以发生变化的drawable,形态变化是通过cornerradius来实现的,颜色变化是通过paint的color来实现的 * 该类在drawable的基础上添加了cornerradius和color两个属性,前者是float类型,后者是int类型 * * a drawable that can morph size, shape (via it's corner radius) and color. specifically this is * useful for animating between a fab and a dialog. */public class morphdrawable extends drawable { private paint paint; private float cornerradius; public static final property corner_radius = new property(float.class, cornerradius) { @override public void set(morphdrawable morphdrawable, float value) { morphdrawable.setcornerradius(value); } @override public float get(morphdrawable morphdrawable) { return morphdrawable.getcornerradius(); } }; public static final property color = new property(integer.class, color) { @override public void set(morphdrawable morphdrawable, integer value) { morphdrawable.setcolor(value); } @override public integer get(morphdrawable morphdrawable) { return morphdrawable.getcolor(); } }; public morphdrawable(@colorint int color, float cornerradius) { this.cornerradius = cornerradius; paint = new paint(paint.anti_alias_flag); paint.setcolor(color); } public float getcornerradius() { return cornerradius; } public void setcornerradius(float cornerradius) { this.cornerradius = cornerradius; invalidateself(); } public int getcolor() { return paint.getcolor(); } public void setcolor(int color) { paint.setcolor(color); invalidateself(); } @override public void draw(canvas canvas) { canvas.drawroundrect(getbounds().left, getbounds().top, getbounds().right, getbounds() .bottom, cornerradius, cornerradius, paint);//hujiawei } @override public void getoutline(outline outline) { outline.setroundrect(getbounds(), cornerradius); } @override public void setalpha(int alpha) { paint.setalpha(alpha); invalidateself(); } @override public void setcolorfilter(colorfilter cf) { paint.setcolorfilter(cf); invalidateself(); } @override public int getopacity() { return paint.getalpha(); }}
5.有了前面的准备之后,就可以在dialog中配置进入和退出的动画效果了,重要代码如下:
//dialogactivity.javapublic void setupsharedeelementtransitions2() { arcmotion arcmotion = new arcmotion(); arcmotion.setminimumhorizontalangle(50f); arcmotion.setminimumverticalangle(50f); interpolator easeinout = animationutils.loadinterpolator(this, android.r.interpolator.fast_out_slow_in); //hujiawei 100是随意给的一个数字,可以修改,需要注意的是这里调用container.getheight()结果为0 morphtransition sharedenter = new morphtransition(contextcompat.getcolor(this, r.color.fab_background_color), contextcompat.getcolor(this, r.color.dialog_background_color), 100, getresources().getdimensionpixelsize(r.dimen.dialog_corners), true); sharedenter.setpathmotion(arcmotion); sharedenter.setinterpolator(easeinout); morphtransition sharedreturn = new morphtransition(contextcompat.getcolor(this, r.color.dialog_background_color), contextcompat.getcolor(this, r.color.fab_background_color), getresources().getdimensionpixelsize(r.dimen.dialog_corners), 100, false); sharedreturn.setpathmotion(arcmotion); sharedreturn.setinterpolator(easeinout); if (container != null) { sharedenter.addtarget(container); sharedreturn.addtarget(container); } getwindow().setsharedelemententertransition(sharedenter); getwindow().setsharedelementreturntransition(sharedreturn);}
6.从上面的分析可以看出,这个方案比较容易扩展,只要是该类型的动画,使用开始和结束时的对应颜色和圆角值就可以构造相应的morphtransition,将morphtransition设置为activity的进入或者退化动画即可。
以上是我的分析和理解,有任何问题欢迎大家指点 �(^ω^)�
原文:fab and dialog morphing animation 
来自: http://www.jcodecraeer.com//a/anzhuokaifa/2015/1215/3776.html
其它类似信息

推荐信息