Android实现一个带粘连效果的LoadingBar

作者:Greenda米 时间:2023-04-26 11:47:41 

前言

我们平时在开发的时候,发起网络请求前,会需要显示一个Loading,一般的做法都是在xml布局上添加好Loading,然后在Activity中,setVisibility来控制Loading的显示和隐藏,这样使用起来就很不方便,因为每一个xml都得引入一个Loading布局。

而LoadingBar就更好的解决了这个问题

最近设计师在外国的一个网站上挑了一个Loading的效果图,尝试实现之后,虽然和原图有点不太一样,但是效果还是不错的。难点就是粘连效果的实现,贝塞尔曲线的点点们简直要把我折磨死了。

先上效果图:

Android实现一个带粘连效果的LoadingBar

实例代码

然后是源码,就是一个简单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));
}
}

“精心”画了一张图,对代码做了说明。

Android实现一个带粘连效果的LoadingBar

在代码中使用


<?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,粘连效果
0
投稿

猜你喜欢

  • SpringMVC中RequestBody注解的List参数传递方式

    2023-06-29 09:56:04
  • 一文看懂RabbitMQ消息丢失如何防止

    2022-03-03 20:36:24
  • Java 爬虫服务器被屏蔽的解决方案

    2022-11-06 13:23:46
  • Java的运算符和程序逻辑控制你了解吗

    2023-01-19 10:01:59
  • SpringBoot配置Profile实现多环境支持

    2023-07-29 21:53:20
  • AJAX SpringBoot 前后端数据交互的项目实现

    2023-11-24 05:49:48
  • Java将字符串String转换为整型Int的两种方式

    2021-12-11 10:01:32
  • Android搜索框通用版

    2022-12-23 09:04:46
  • IDEA配置JRebel实现热部署的方法

    2022-08-28 20:53:00
  • java 读取网页内容的实例详解

    2023-11-27 22:38:11
  • win10和win7下java开发环境配置教程

    2022-05-01 05:34:22
  • native.js获取手机硬件基本信息实例代码android版

    2023-10-19 13:33:09
  • JDK8中新增的原子性操作类LongAdder详解

    2023-06-19 22:02:58
  • C#中Razor模板引擎简单使用

    2022-01-21 10:04:13
  • Java中实现可拖放图片剪裁入门教程

    2022-04-23 12:11:03
  • Java基础之Web服务器与Http详解

    2021-08-13 16:39:42
  • IntelliJ IDEA 2017.1.4 x64配置步骤(介绍)

    2022-02-25 13:48:48
  • 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
  • asp之家 软件编程 m.aspxhome.com