Android实现一个带粘连效果的LoadingBar
作者:Greenda米 时间:2023-04-26 11:47:41
前言
我们平时在开发的时候,发起网络请求前,会需要显示一个Loading,一般的做法都是在xml布局上添加好Loading,然后在Activity中,setVisibility来控制Loading的显示和隐藏,这样使用起来就很不方便,因为每一个xml都得引入一个Loading布局。
而LoadingBar就更好的解决了这个问题
最近设计师在外国的一个网站上挑了一个Loading的效果图,尝试实现之后,虽然和原图有点不太一样,但是效果还是不错的。难点就是粘连效果的实现,贝塞尔曲线的点点们简直要把我折磨死了。
先上效果图:
实例代码
然后是源码,就是一个简单VIew,可以直接放在xml中使用。
package top.greendami.greendami;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by GreendaMi on 2017/3/17.
*/
public class PPView extends View {
String TAG = "PPView";
//动画开关
boolean isLoading = true;
Context mContext;
private int mWidth = 100;
private int mheight = 100;
public int mColor;
public Paint mPaint = new Paint();
float time = 0;
//小球与中间打球的最远距离
float distance = 100;
public PPView(Context context) {
super(context);
mContext = context;
}
public PPView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mContext = context;
mColor = context.getResources().getColor(R.color.colorPrimary);
init();
}
private void init() {
mPaint.setAntiAlias(true);
mPaint.setColor(mColor);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
//宽度至少是高度的4倍
if (widthSpecSize < 4 * heightSpecSize) {
widthSpecSize = 4 * heightSpecSize;
}
mWidth = widthSpecSize;
mheight = heightSpecSize;
distance = 1.2f * mheight;
setMeasuredDimension(widthSpecSize, heightSpecSize);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isLoading) {
//大圆半径
float bigR = mheight * 0.32f + mheight * 0.03f * Math.abs((float) Math.sin(Math.toRadians(time)));
float smallR = mheight * 0.22f + mheight * 0.03f * Math.abs((float) Math.cos(Math.toRadians(time)));
float bigx = (getWidth()) / 2;
//画中间大圆
canvas.drawCircle(bigx, mheight / 2, bigR, mPaint);
float smalx = getSmallCenterX();
//画小圆
canvas.drawCircle(smalx, mheight / 2, smallR, mPaint);
//画链接
//小球在右侧
if (smalx > bigx) {
Path path = new Path();
//上面的贝塞尔曲线的第一个点,在大圆身上
float x1 = bigx + bigR * (float) Math.cos(Math.toRadians(time));
float y1 = mheight / 2 - bigR * (float) Math.sin(Math.toRadians(time));
if (y1 > mheight / 2 - smallR) {
y1 = mheight / 2 - smallR;
x1 = bigx + (float) (Math.sqrt(bigR * bigR - smallR * smallR));
}
//上面的贝塞尔曲线的第三个点,在小圆身上
float x2 = smalx - smallR * (float) Math.cos(Math.toRadians(time));
float y2 = mheight / 2 - smallR * (float) Math.sin(Math.toRadians(time));
if (y2 > mheight / 2 - smallR * 0.8) {
y2 = mheight / 2 - smallR * 0.8f;
x2 = smalx - smallR * (float) (Math.sqrt(1-0.64f));
}
//下面的贝塞尔曲线的第三个点,在小圆身上
float x3 = smalx - smallR * (float) Math.cos(Math.toRadians(time));
float y3 = mheight / 2 + smallR * (float) Math.sin(Math.toRadians(time));
if (y3 < mheight / 2 + smallR * 0.8) {
y3 = mheight / 2 + smallR * 0.8f;
x3 = smalx - smallR * (float) (Math.sqrt(1-0.64f));
}
//下面的贝塞尔曲线的第一个点,在大圆身上
float x4 = bigx + bigR * (float) Math.cos(Math.toRadians(time));
float y4 = mheight / 2 + bigR * (float) Math.sin(Math.toRadians(time));
if (y4 < mheight / 2 + smallR) {
y4 = mheight / 2 + smallR;
x4 = bigx + (float) (Math.sqrt(bigR * bigR - smallR * smallR));
}
path.moveTo(x1, y1);
path.quadTo((bigx + smalx) / 2, mheight / 2, x2, y2);
// 绘制贝赛尔曲线(Path)
path.lineTo(x3, y3);
path.quadTo((bigx + smalx) / 2, mheight / 2, x4, y4);
canvas.drawPath(path, mPaint);
}
//小球在左侧
if (smalx < bigx) {
Path path = new Path();
float x1 = bigx + bigR * (float) Math.cos(Math.toRadians(time));
float y1 = mheight / 2 - bigR * (float) Math.sin(Math.toRadians(time));
if (y1 > mheight / 2 - smallR) {
y1 = mheight / 2 - smallR;
x1 = bigx - (float) (Math.sqrt(bigR * bigR - smallR * smallR));
}
float x2 = smalx - smallR * (float) Math.cos(Math.toRadians(time));
float y2 = mheight / 2 - smallR * (float) Math.sin(Math.toRadians(time));
if (y2 > mheight / 2 - smallR * 0.8) {
y2 = mheight / 2 - smallR * 0.8f;
x2 = smalx + smallR * (float) (Math.sqrt(1-0.64f));
}
float x3 = smalx - smallR * (float) Math.cos(Math.toRadians(time));
float y3 = mheight / 2 + smallR * (float) Math.sin(Math.toRadians(time));
if (y3 < mheight / 2 + smallR * 0.8) {
y3 = mheight / 2 + smallR * 0.8f;
x3 = smalx + smallR * (float) (Math.sqrt(1-0.64f));
}
float x4 = bigx + bigR * (float) Math.cos(Math.toRadians(time));
float y4 = mheight / 2 + bigR * (float) Math.sin(Math.toRadians(time));
if (y4 < mheight / 2 + smallR) {
y4 = mheight / 2 + smallR;
x4 = bigx - (float) (Math.sqrt(bigR * bigR - smallR * smallR));
}
path.moveTo(x1, y1);
path.quadTo((bigx + smalx) / 2, mheight / 2, x2, y2);
// 绘制贝赛尔曲线(Path)
path.lineTo(x3, y3);
path.quadTo((bigx + smalx) / 2, mheight / 2, x4, y4);
canvas.drawPath(path, mPaint);
}
postInvalidate();
}
}
//计算小球的X坐标
private float getSmallCenterX() {
//此处控制速度
time = time + 2.5f;
return mWidth / 2 + distance * (float) Math.cos(Math.toRadians(time));
}
}
“精心”画了一张图,对代码做了说明。
在代码中使用
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white" tools:context="top.greendami.greendami.MainActivity">
<top.greendami.greendami.PPView
android:layout_centerInParent="true"
android:layout_width="400dp"
android:layout_height="80dp" />
</RelativeLayout>
来源:http://www.jianshu.com/p/f7c164288aca
标签:android,loadingbar,粘连效果
![](/images/zang.png)
![](/images/jiucuo.png)
猜你喜欢
SpringMVC中RequestBody注解的List参数传递方式
2023-06-29 09:56:04
一文看懂RabbitMQ消息丢失如何防止
2022-03-03 20:36:24
![](https://img.aspxhome.com/file/2023/9/64139_0s.jpg)
Java 爬虫服务器被屏蔽的解决方案
2022-11-06 13:23:46
![](https://img.aspxhome.com/file/2023/4/77124_0s.png)
Java的运算符和程序逻辑控制你了解吗
2023-01-19 10:01:59
SpringBoot配置Profile实现多环境支持
2023-07-29 21:53:20
![](https://img.aspxhome.com/file/2023/9/85419_0s.png)
AJAX SpringBoot 前后端数据交互的项目实现
2023-11-24 05:49:48
![](https://img.aspxhome.com/file/2023/7/59857_0s.png)
Java将字符串String转换为整型Int的两种方式
2021-12-11 10:01:32
![](https://img.aspxhome.com/file/2023/9/86769_0s.png)
Android搜索框通用版
2022-12-23 09:04:46
![](https://img.aspxhome.com/file/2023/1/139641_0s.gif)
IDEA配置JRebel实现热部署的方法
2022-08-28 20:53:00
![](https://img.aspxhome.com/file/2023/1/100051_0s.png)
java 读取网页内容的实例详解
2023-11-27 22:38:11
win10和win7下java开发环境配置教程
2022-05-01 05:34:22
![](https://img.aspxhome.com/file/2023/6/79866_0s.png)
native.js获取手机硬件基本信息实例代码android版
2023-10-19 13:33:09
JDK8中新增的原子性操作类LongAdder详解
2023-06-19 22:02:58
![](https://img.aspxhome.com/file/2023/3/76303_0s.jpg)
C#中Razor模板引擎简单使用
2022-01-21 10:04:13
Java中实现可拖放图片剪裁入门教程
2022-04-23 12:11:03
Java基础之Web服务器与Http详解
2021-08-13 16:39:42
![](https://img.aspxhome.com/file/2023/7/81907_0s.png)
IntelliJ IDEA 2017.1.4 x64配置步骤(介绍)
2022-02-25 13:48:48
![](https://img.aspxhome.com/file/2023/5/71885_0s.jpg)
Android编程实现为ListView创建上下文菜单(ContextMenu)的方法
2021-12-09 06:26:28
Spring+Junit4进行接口测试实例代码
2021-09-15 07:44:06
零基础学Java:Java开发工具 Eclipse 安装过程创建第一个Java项目及Eclipse的一些基础使用技巧
2022-09-05 03:46:03
![](https://img.aspxhome.com/file/2023/3/69953_0s.png)