Android中模仿抖音加载框之两颗小球转动效果

所属分类: 软件编程 / Android 阅读数: 61
收藏 0 赞 0 分享

安卓版抖音v2.5加载框:

效果图如下所示:

抖音加载框

本控件效果图:

本控件

使用方法

源码地址:Android仿抖音加载框之两颗小球转动控件

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方式实现:

xfermode

从上图可以看出用Darken、Lighten、Screen模式可以做到让叠加处上色,但是颜色不能自定义。

 思路2:通过path的OP操作实现(API19):

op

(图片摘自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中模仿抖音加载框之两颗小球转动控件效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

更多精彩内容其他人还在看

使用ViewPager实现android软件使用向导功能实现步骤

现在的大部分android软件,都是使用说明,就是第一次使用该软件时,会出现向导,可以左右滑动,然后就进入应用的主界面了,下面我们就实现这个功能
收藏 0 赞 0 分享

android在异步任务中关闭Cursor的代码方法

android在异步任务中如何关闭Cursor?在我们开发应用的时候,很多时候会遇到这种问题,下面我们就看看代码如何实现
收藏 0 赞 0 分享

Android自定义桌面功能代码实现

android自定义桌面其实很简单,看一个例子就明白了
收藏 0 赞 0 分享

android将图片转换存到数据库再从数据库读取转换成图片实现代码

有时候我们想把图片存入到数据库中,尽管这不是一种明智的选择,但有时候还是不得以会用到,下面说说将图片转换成byte[]数组存入到数据库中去,并从数据库中取出来转换成图像显示出来
收藏 0 赞 0 分享

TextView显示系统时间(时钟功能带秒针变化

用System.currentTimeMillis()可以获取系统当前的时间,我们可以开启一个线程,然后通过handler发消息,来实时的更新TextView上显示的系统时间,可以做一个时钟的功能
收藏 0 赞 0 分享

Android用ListView显示SDCard文件列表的小例子

本文简单实现了用ListView显示SDCard文件列表,目录的回退等功能暂不讨论,获取文件列表,files即为所选择目录下的所有文件列表
收藏 0 赞 0 分享

Android拦截外拨电话程序示例

这篇文章主要介绍了Android拦截外拨电话的示例,大家参考使用吧
收藏 0 赞 0 分享

通过Html网页调用本地安卓(android)app程序代码

如何使用html网页和本地app进行传递数据呢?经过研究,发现还是有方法的,总结了一下,大致有一下几种方式
收藏 0 赞 0 分享

android Textview文字监控(Textview使用方法)

以手机号充值为例,当用户输入最后一位数时候,进行汇率的变换,本文就实现类似这样的功能
收藏 0 赞 0 分享

Android ListView长按弹出菜单二种实现方式示例

这篇文章主要介绍了Android ListView长按弹出菜单的方法,大家参考实现
收藏 0 赞 0 分享
查看更多