依然是个收藏已久的Gif,今天来实现一下。

记忆里好像是有人已经实现过了。刚才去找了下,又没找到。如果哪个朋友看到过过,给我发下,我来对比下,我想总会又收获的。Gif如下图。

效果图如下:

原理

原理也不复杂。就是用Path 定义个圆型的轨迹。不停的获取该圆形的轨迹的xy坐标。

黑色圆 运行在该path 的上半圆。空心圆运行在该Path的下半圆。

如 图如下:

初始化

根据个数据准备好圆形。

public class AlterCircleView extends BaseView {private int mNumber = 5;
//--------------------------------------------------------------// 圆 属性private int mRadius = DisplayUtils.dp2px(this.getContext(), 10);// 交替的两个圆private Circle mCurrCircle, mNextCircle;private Circle[] mCircles = new Circle[mNumber];private List<Path> mPaths = new ArrayList<>();
//--------------------------------------------------------------// 测量 围绕的中心圆 属性float distance = 0.0f;float pos[] = new float[2];float tan[] = new float[2];// 测量圆的measureprivate PathMeasure measure;// 指定当前第几个 圆Path 总数为 number-1private int index = 0;
//--------------------------------------------------------------// 黑色圆形, 去为 false  ,回来 为 trueprivate boolean mBack = false;public AlterCircleView(Context context) {this(context, null);}public AlterCircleView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public AlterCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);List<Circle> list = new CircleFactory(mRadius).generateCircles(mNumber);for (int i = 0; i < list.size(); i++) {mCircles[i] = list.get(i);}mCurrCircle = mCircles[0]; // 黑色圆mNextCircle = mCircles[1];measure = new PathMeasure();}
复制代码

测量

    @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int widthMode = MeasureSpec.getMode(widthMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);int width = MeasureSpec.getSize(widthMeasureSpec);int height = MeasureSpec.getSize(heightMeasureSpec);int measuredWidth = width, measuredHeight = height;if (widthMode != MeasureSpec.EXACTLY) {measuredWidth = mRadius * 2 * mNumber + mRadius * (mNumber - 1) + mMargin * 2 + mPadding * 2;}if (heightMode != MeasureSpec.EXACTLY) {// 当两个圆,交替到 垂直状态,+ 2个半径 也就是 最大的高度。int r = mNextCircle.getX() - mCurrCircle.getX();measuredHeight = r + mRadius * 2 + mMargin + mPadding;}setMeasuredDimension(measuredWidth, measuredHeight);}
复制代码

旋转圆的Path

测量完成,也就是说所有的数据已经准备好,然后在该方法中初始化 mNumber-1 个旋转圆的Path

    @Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);// 两个圆形 中间的 旋转圆,Path 路径for (int i = 0; i < mCircles.length - 1; i++) {Circle currCircle = mCircles[i];Circle nextCircle = mCircles[i + 1];int r = (nextCircle.getX() + currCircle.getX()) / 2;int radius = r - currCircle.getX();Path path = new Path();path.addCircle(r, 0, radius, Path.Direction.CW);mPaths.add(path);}}
复制代码

绘制以及处理逻辑

    @Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.translate(mMargin + mPadding + mRadius, mViewHeight / 2);canvas.save();for (Circle c : mCircles) {boolean solid = c.getSolid();mPaint.setStyle(Paint.Style.STROKE);if (solid)mPaint.setStyle(Paint.Style.FILL_AND_STROKE);canvas.drawCircle(c.getX(), c.getY(), c.getRadius(), mPaint);}// index 来 设置 要 测量的pathmeasure.setPath(mPaths.get(index), false);// 获取当前 点的 xy坐标,以及正切(此处没用)measure.getPosTan(distance, pos, tan);mNextCircle.setX((int) pos[0]);mNextCircle.setY((int) pos[1]);
复制代码

黑色圆-去: distance 初始化值为0.位置为圆心右手边。
mNextCircle圆形跟随该路径移动至180度位置。
然后,黑色圆形则从180度的位置+distance开始移动至360/0度的位置。

黑色圆-回: 同理。

        //黑色圆-去:if (!mBack) {if (distance < measure.getLength() / 2) {float f = measure.getLength() / 2 + distance;float pos[] = new float[2];float tan[] = new float[2];measure.getPosTan(f, pos, tan);mCurrCircle.setX((int) pos[0]);mCurrCircle.setY((int) pos[1]);distance += 2;} else {// 交换2个圆位置Circle temp = mCircles[index];mCircles[index] = mCircles[index + 1];mCircles[index + 1] = temp;if (index < mPaths.size() - 1) {index++;distance = 0;mCurrCircle = mCircles[index];mNextCircle = mCircles[index + 1];} else {distance = measure.getLength() / 2;mBack = true;}}}//黑色圆-回:else {if (distance < measure.getLength()) {float f = distance - measure.getLength() / 2;float pos[] = new float[2];float tan[] = new float[2];measure.getPosTan(f, pos, tan);mCurrCircle.setX((int) pos[0]);mCurrCircle.setY((int) pos[1]);distance += 2;} else {Circle temp = mCircles[index];mCircles[index] = mCircles[index + 1];mCircles[index + 1] = temp;if (index > 0) {index--;distance = measure.getLength() / 2;mCurrCircle = mCircles[index + 1];mNextCircle = mCircles[index];} else {distance = 0;mBack = false;}}}postInvalidate();canvas.restore();}
}
复制代码

src下载

转载于:https://juejin.im/post/5ae2f85f6fb9a07aab299648

Gif(1)-加载视图-交替圆效果相关推荐

  1. RecyclerView加载不同view实现效果--IT蓝豹

    本项目由开发者:黄洞洞精心为初学者编辑RecyclerView的使用方法. RecyclerView加载不同view实现效果,支持加载多个view,并且支持用volley获取数据, 项目主要介绍: 初 ...

  2. Android进度条/等待加载——旋转小圆点效果

    进度条/等待加载--旋转小圆点效果 1 效果图 2.思想 12个小圆点叠放(i=0,1,-11) 动画一:依次从0度旋转到30i度 动画二:依次从30i度旋转到360度 因为不牵扯用户交互,所以用最基 ...

  3. 环形动画加载视图AnimatedCircleLoadingView​​​​​​​

    2019独角兽企业重金招聘Python工程师标准>>> 环形动画加载视图AnimatedCircleLoadingView AnimatedCircleLoadingView是基于A ...

  4. 环形动画加载视图AnimatedCircleLoadingView

    环形动画加载视图AnimatedCircleLoadingView AnimatedCircleLoadingView是基于Android手表动画android-watch-loading-anima ...

  5. html加载完显示图片,js图片未加载完显示loading效果

    js图片未加载完显示loading效果 img{float:left;200px;height:200px;margin:0 10px 10px 0} //判断浏览器 var Browser=new ...

  6. 安卓设置菊花动画_Android仿ios加载loading菊花图效果

    项目中经常会用到加载数据的loading显示图,除了设计根据app自身设计的动画loading,一般用的比较多的是仿照ios 的菊花加载loading 图,当然一些条件下还会涉及到加载成功/ 失败情况 ...

  7. js文件代码未加载或者没有js效果

    问题:在页面中js文件中的代码未加载或者没有任何效果. 原因: 成功引用了js文件,但无效果或者提示未加载该文档中的代码. 可能页面引用js文件的路径存在问题 解决: 重新检查你引用的js文件的路径是 ...

  8. html怎么帮图片占位,css+html实现Skeleton Screen 加载占位图动画效果(带动画)

    效果 自上而下渐隐渐现 源码 html,用的angular语法,只要做简单的修改就可以成为你需要的语法 css .skeletonItem { padding: 16px; border-bottom ...

  9. ajax 滚动加载 缓存,Ajax实现加载缓存的loding效果

    这次给大家带来Ajax实现加载缓存的loding效果,Ajax实现加载缓存loding效果的注意事项有哪些,下面就是实战案例,一起来看一下. Ajax 异步请求的时候,一般都会利用一个动态的 gif小 ...

最新文章

  1. 技术“摸鱼” 大神,国外小哥 5 年白拿 45 万工资!
  2. 如何安装体验 Ubuntu on Windows
  3. nginx搭建文件服务器脚本,nginx搭建web服务器,配置端口复用
  4. Host 'controller' is not mapped to any cell
  5. java 常用流_Java流类图结构: 流的概念和作用流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数...
  6. c语言贪吃蛇最简单代码_C语言指针,这可能是史上最干最全的讲解啦(附代码)!!!...
  7. java类成员方法(成员函数)的初步介绍
  8. linux tomcat PermGen space
  9. 只有它才能让云计算、大数据、人工智能大放异彩?它究竟有什么魔力?
  10. JavaScript(一)基本语法
  11. Xposed (二) 深入Module
  12. 【收藏】韦东山嵌入式Linux课程梳理|随时更新
  13. cnvd与cnnvd区别_漏洞编码CVE/CAN/BUGTRAQ/CNCVE/CNVD/CNNVD都指什么?
  14. 一个链接搞定源码下载
  15. 埃默里大学有计算机专业吗,埃默里大学计算机专业
  16. 身份证实名认证java后台代码
  17. Python | pandas 计算每行的增长率与累计增长率
  18. AFX_MODULE_STATE作用
  19. 【毕业设计】基于机器学习的餐厅销量预测 -大数据 python
  20. html网页如何在手机上观看,电脑的html怎么在手机观看

热门文章

  1. php mysql用户登录_php mysql实现用户登录功能的代码示例
  2. 温度转换的python程序_Python通过小实例入门学习---1.0(温度转换)
  3. 如何删除oracle用户数据库用户,oracle删除指定用户的原数据库,建立该用户的新数据库...
  4. linux开机启动遇到grub启动_Linux如何跳过grub启动
  5. centos 配置bond_CentOS 网卡配置bond4(LACP)
  6. 让浏览器判断html为手机页面,判断是从手机端还是客户端访问的页面,判断浏览器类型...
  7. 嵌入式linux编译环境搭建,嵌入式Linux开发环境搭建
  8. 机械爪的带有压力反馈的控制实验
  9. java list合并_Java流系列之第2部:使用流执行聚合
  10. mysql数据库导出_MySQL数据库导入导出详解[转发]