Android加载框 小球转动 Android中模仿抖音加载框之两颗小球转动效果
勇朝陈 人气:0安卓版抖音v2.5加载框:
效果图如下所示:
本控件效果图:
使用方法
1、xml引用:
<com.douyinloadingview.DYLoadingView android:id="@+id/dy3" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#000000" app:color1="#FF00EEEE" app:color2="#FFFF4040" app:....(其他可选属性) />
2、java使用:
@BindView(R.id.dy1) DYLoadingView dy1; @OnClick(R.id.b1) void start() { dy1.setXXXXX; //设置属性(可选) dy1.start(); //开始动画 } @OnClick(R.id.b2) void stop() { dy1.stop(); //停止动画 }
就酱。
可用属性
名称 | 对应xml属性 | 对应java方法 | 默认值 |
---|---|---|---|
球1半径 | radius1 | setRadius() | 6dp |
球2半径 | radius2 | setRadius() | 6dp |
两球间隔 | gap | setRadius() | 0.8dp |
球1颜色 | color1 | setColors() | 0XFFFF4040 |
球2颜色 | color2 | setColors() | 0XFF00EEEE |
叠加色 | mixColor | setColors() | 0XFF000000 |
从右往左移动时小球最大缩放倍数 | rtlScale | setScales() | 0.7f |
从左往右移动时小球最大缩放倍数 | ltrScale | setScales() | 1.3f |
一次移动动画时长 | duration | setDuration() | 350ms |
一次移动动画后停顿时长 | pauseDuration | setDuration() | 80ms |
动画进度在[0,scaleStartFraction]期间,小球大小逐渐缩放 | scaleStartFraction | setStartEndFraction() | 0.2f |
动画进度在[scaleEndFraction,1]期间,小球大小逐渐恢复 | scaleEndFraction | setStartEndFraction() | 0.8f |
(rtl = right to left, ltr = left to right)
部分属性说明:
•color格式为32位ARGB
•scaleStartFraction范围[0,0.5];scaleEndFraction范围[0.5,1]
•假设ltrScale = 1.3,scaleStartFraction = 0.2,scaleEndFraction = 0.8;那么实际效果就是一颗小球从左边开始向右移动
期间,进度在0%~20%时半径逐渐从1倍放大到1.3倍,在20%~80%期间大小保持1.3倍,在80%~100%时半径逐渐从1.3倍恢复至1倍
实现思路
要让小球动,当然要有一个动画,通过动画来获得一个进度百分比fraction,然后小球在动画过程中的坐标、大小就可以通过这个值来计算:
private void initAnim() { fraction = 0.0f; stop(); anim = ValueAnimator.ofFloat(0.0f, 1.0f); anim.setDuration(duration); if (pauseDuration > 0) { anim.setStartDelay(pauseDuration); anim.setInterpolator(new AccelerateDecelerateInterpolator()); } else { anim.setRepeatCount(ValueAnimator.INFINITE); anim.setRepeatMode(ValueAnimator.RESTART); anim.setInterpolator(new LinearInterpolator()); } anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { fraction = animation.getAnimatedFraction(); invalidate(); } }); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { isLtr = !isLtr; } @Override public void onAnimationRepeat(Animator animation) { isLtr = !isLtr; } @Override public void onAnimationCancel(Animator animation) { isAnimCanceled = true; } @Override public void onAnimationEnd(Animator animation) { if (!isAnimCanceled) { anim.start(); } } }); }
代码中看到,如果小球一次移动后不需要停顿(pauseDuration = 0),那么直接通过anim.setRepeatCount(ValueAnimator.INFINITE)让动画无限循环,否则的话就要通过anim.setStartDelay(pauseDuration)
来设置停顿时间,然后在监听的onAnimationEnd里重启动画,以此实现每一次移动后小球能停顿一定时间。在onAnimationUpdate里,我们记录了当前动画百分比fraction,然后通过invalidate()重绘,在之后的onDraw里将通过该值画出小球。另外,每次动画开始时(或是重复时),会将isLtr取反,这个标志位的作用是标明当前哪颗球在【从左往右】移动,因为两颗球的颜色、初始半径是不一样的嘛,onDraw里画小球时是需要这个标志位协助的。
有了动画进度fraction和标志位isLtr后,就可以在onDraw里画出小球了。
**首先要计算小球当前的坐标**。y坐标永远是固定的,不谈,x坐标随着`fraction`的变化而变化。两颗球之间最远距离为球1半径+球2半径+两球间隔,即`distance = gap + radius1 + radius2;`,这个值就是两颗球的移动范围,由此可计算出,当前【从左往右】移动的小球的x坐标和当前【从右往左】移动的小球x坐标分别为:
float ltrX = getMeasuredWidth() / 2.0f - distance / 2.0f; ltrX = ltrX + (distance * fraction); float rtlX = getMeasuredWidth() / 2.0f + distance / 2.0f; rtlX = rtlX - (distance * fraction);
**接下来要计算小球当前的大小**。小球的大小也是随着动画进度变化的,上面已经说明了`scaleStartFraction`和`scaleEndFraction`属性的含义。 以当前小球【从左往右】移动为例,当动画进度为0时,小球大小为初始1倍大小;当动画进度到scaleStartFraction时,小球大小将缩放到`ltrScale`倍,当动画进度为[scaleStartFraction,scaleEndFraction]范围时,小球大小保持`ltrScale`倍,当动画进度到[scaleEndFraction,1]范围时,小球则从`ltrScale`倍逐渐恢复至1倍。 为了便于计算,首先将`[0,scaleStartFraction]`转换为`[0,1.0]`的真实百分比,根据`y = kx + b`(就这么个入门公式。。我都要在纸上算一遍T-T),可以得出:`float scaleFraction = 1.0f / scaleStartFraction * fraction; `,有了这个真实百分比,那么该区间里小球当前半径就好计算了:
ltrBallRadius = ltrInitRadius * (1 + (ltrScale - 1) * scaleFraction); rtlBallRadius = rtlInitRadius * (1 + (rtlScale - 1) * scaleFraction);
应该好懂的吧。另外[scaleEndFraction,1]区间里小球当前半径计算思路是一样的,不谈。
最后就是要画出小球。这里主要是如何画出实现两球叠加的部分的颜色。
思路1:通过xfermode方式实现:
从上图可以看出用Darken、Lighten、Screen模式可以做到让叠加处上色,但是颜色不能自定义。
思路2:通过path的OP操作实现(API19):
(图片摘自http://www.gcssloop.com/customview/Path_Over)
因此,可以先构造两个小球的Path,然后再将这两个Path进行INTERSECT操作,即可获得叠加处的Path,这样就可以做到自定义叠加处的颜色了。
onDraw完整代码:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); float centerY = getMeasuredHeight() / 2.0f; float ltrInitRadius, rtlInitRadius; Paint ltrPaint, rtlPaint; //确定当前【从左往右】移动的是哪颗小球 if (isLtr) { ltrInitRadius = radius1; rtlInitRadius = radius2; ltrPaint = paint1; rtlPaint = paint2; } else { ltrInitRadius = radius2; rtlInitRadius = radius1; ltrPaint = paint2; rtlPaint = paint1; } float ltrX = getMeasuredWidth() / 2.0f - distance / 2.0f; ltrX = ltrX + (distance * fraction);//当前从左往右的球的X坐标 float rtlX = getMeasuredWidth() / 2.0f + distance / 2.0f; rtlX = rtlX - (distance * fraction);//当前从右往左的球的X坐标 //计算小球移动过程中的大小变化 float ltrBallRadius, rtlBallRadius; if (fraction <= scaleStartFraction) { //动画进度[0,scaleStartFraction]时,球大小由1倍逐渐缩放至ltrScale/rtlScale倍 float scaleFraction = 1.0f / scaleStartFraction * fraction; //百分比转换 [0,scaleStartFraction]] -> [0,1] ltrBallRadius = ltrInitRadius * (1 + (ltrScale - 1) * scaleFraction); rtlBallRadius = rtlInitRadius * (1 + (rtlScale - 1) * scaleFraction); } else if (fraction >= scaleEndFraction) { //动画进度[scaleEndFraction,1],球大小由ltrScale/rtlScale倍逐渐恢复至1倍 float scaleFraction = (fraction - 1) / (scaleEndFraction - 1); //百分比转换,[scaleEndFraction,1] -> [1,0] ltrBallRadius = ltrInitRadius * (1 + (ltrScale - 1) * scaleFraction); rtlBallRadius = rtlInitRadius * (1 + (rtlScale - 1) * scaleFraction); } else { //动画进度[scaleStartFraction,scaleEndFraction],球保持缩放后的大小 ltrBallRadius = ltrInitRadius * ltrScale; rtlBallRadius = rtlInitRadius * rtlScale; } ltrPath.reset(); ltrPath.addCircle(ltrX, centerY, ltrBallRadius, Path.Direction.CW); rtlPath.reset(); rtlPath.addCircle(rtlX, centerY, rtlBallRadius, Path.Direction.CW); mixPath.op(ltrPath, rtlPath, Path.Op.INTERSECT); canvas.drawPath(ltrPath, ltrPaint); canvas.drawPath(rtlPath, rtlPaint); canvas.drawPath(mixPath, mixPaint); }
总结
以上所述是小编给大家介绍的Android中模仿抖音加载框之两颗小球转动控件效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
加载全部内容