Android 自定义控件 loding小球

2024-08-30 16:32

本文主要是介绍Android 自定义控件 loding小球,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

以下为参照博客    http://blog.csdn.net/guimianhao9833/article/details/74858472 


首先看下效果图:

步骤:
1.继承view,并需要三个构造函数。
public MyView(Context context) {//注意不要默认实现,记得修改。
    this(context, null);
}public MyView(Context context, AttributeSet attrs) {//注意不要默认实现,记得修改。
    this(context, attrs, 0);
}public MyView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);
    //初始化工作
    init(context, attrs);
}
初始化工作init:
1)在attrs.xml中定义控件需要的属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyView">
        <attr name="color" format="color"/>
        <attr name="text" format="string"/>
    </declare-styleable>
</resources>
2)自定义控件一般都需要定义相关的属性,我们获取它并对它进行相关的设置;
由效果图可知,这个自定义控件需要定义一个画笔用来画图形路径;
需要定义一个画笔用来画文字;
需要Path用来定义闭合波浪路径;
为了实现控件无线循环的动画效果,需要对其进行相关的监听动作并实时刷新。
private void init(Context context, AttributeSet attrs) {//1.定义需要的属性
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyView);
    //颜色和文字
    color = a.getColor(R.styleable.MyView_color, Color.rgb(238,121,66));
    text = a.getString(R.styleable.MyView_text);
    //记得调用这个方法回收
    a.recycle();
    //2.1定义图形及路径填充画笔的相关值(抗锯齿、填充、防抖动)
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPaint.setStyle(Paint.Style.FILL);
    mPaint.setColor(color);
    mPaint.setDither(true);
    //2.2定义文字画笔的相关值(抗锯齿、白色、粗体)
    textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    textPaint.setColor(Color.WHITE);
    textPaint.setTypeface(Typeface.DEFAULT_BOLD);
    //2.3定义闭合波浪路径
    path = new Path();
    //3.实现无线循环的动画效果
    //ValueAnimator定时器,属性动画ObjectAnimator就是它的一个子类
    ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
    //让动画无限重复,每次从头开始,一个周期1000毫秒
    animator.setDuration(1000);
    animator.setRepeatCount(ValueAnimator.INFINITE);
    animator.setRepeatMode(ValueAnimator.RESTART);
    //补上一个线性插值器,使得动画流畅
    animator.setInterpolator(new LinearInterpolator());
    //监听获得过程值,实时进行刷新
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Override
        public void onAnimationUpdate(ValueAnimator animation) {currentPercent = animation.getAnimatedFraction();
            //刷新
            invalidate();
        }});
    //动画开始
    animator.start();
}
 2.onDraw方法,重中之重!
绘制流程:

1)绘制底部蓝色的文字
2)绘制闭合的波浪路径,颜色为蓝色
3)绘制白色的文字
4)根据已有的波浪路径去裁剪文字,使得文字上半部门为蓝色,文字下半部门为白色
(因为先绘制在下部,后绘制的在上部)
5)在已有的画布canvas上画一个圆,也就是裁剪成圆形
@Override
protected void onDraw(Canvas canvas) {//super.onDraw(canvas);
    //1.画底部蓝色的字
    textPaint.setColor(color);
    drawCenterText(canvas, textPaint, "");
    //2.画上层白色的字
    textPaint.setColor(Color.WHITE);
    //3.生成闭合波浪路径
    path = getActionPath(currentPercent);
    //4.剪裁文字
    canvas.clipPath(path);
    //5.剪裁成圆形(SRC 源像素)
    canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, mPaint);
    mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
    //6.画波浪(DST 目标像素)
    canvas.drawPath(path, mPaint);
    mPaint.setXfermode(null);
    drawCenterText(canvas, textPaint, "");
}
生成闭合的波浪路径的方法getActionPath:
这个波浪可以由 二阶贝塞尔曲线。如下的例子,起点为(100,100),然后移动相对于起点的两个位置变化为(150,0),(200,100)。
Path path=new Path();
path.moveTo(100,100);
path.rQuadTo(50,-100,100,0);
               图解:

1)画两个周期的波浪
2)画右侧的直线
3)画下边的直线
private Path getActionPath(float percent) {Path path = new Path();
    int x = -mWidth;
    //1.当前x点坐标(根据动画进度水平推移,一个动画周期推移的距离为一个mWidth    x += percent * mWidth;
    //2.波形的起点
    path.moveTo(x, mHeight / 2);
    //控制点的相对宽度
    int kongzhiWidth = mWidth / 4;
    //控制点的相对高度=mHeight的二十分之3
    int kongzhiHeight = mHeight / 20 * 3;
    //3.画第一个周期,一个周期为一上一下
    path.rQuadTo(kongzhiWidth, kongzhiHeight, kongzhiWidth * 2, 0);
    path.rQuadTo(kongzhiWidth, -kongzhiHeight, kongzhiWidth * 2, 0);
    //画第二个周期,如此循环下去
    path.rQuadTo(kongzhiWidth, kongzhiHeight, kongzhiWidth * 2, 0);
    path.rQuadTo(kongzhiWidth, -kongzhiHeight, kongzhiWidth * 2, 0);
    //4.画右侧的直线
    path.lineTo(x + mWidth * 2, mHeight);
    //5.画下边的直线
    path.lineTo(x, mHeight);
    //自动闭合补出左边的直线
    path.close();
    return path;
}
   画中间的文字drawCenterText:
private void drawCenterText(Canvas canvas, Paint textPaint, String text) {//画一个规定位置的矩形
    Rect rect = new Rect(0, 0, mWidth, mHeight);
    //由于默认是位于左边的,所以这样设置到中间来。
    textPaint.setTextAlign(Paint.Align.CENTER);
    Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
    float top = fontMetrics.top;
    float bottom = fontMetrics.bottom;

    int centerY = (int) (rect.centerY() - top / 2 - bottom / 2);
    canvas.drawText(text, rect.centerX(), centerY, textPaint);
}
3.onMeasure方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    if (widthMode == MeasureSpec.EXACTLY) {mWidth = widthSize;
    }if (heightMode == MeasureSpec.EXACTLY) {mHeight = heightSize;
    }setMeasuredDimension(mWidth, mHeight);
    textSize = mWidth / 2;
    textPaint.setTextSize(textSize);
}
自定义控件,要好好学哦。

这篇关于Android 自定义控件 loding小球的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1121338

相关文章

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

Android ClassLoader加载机制详解

《AndroidClassLoader加载机制详解》Android的ClassLoader负责加载.dex文件,基于双亲委派模型,支持热修复和插件化,需注意类冲突、内存泄漏和兼容性问题,本文给大家介... 目录一、ClassLoader概述1.1 类加载的基本概念1.2 android与Java Class

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

一文详解Java Stream的sorted自定义排序

《一文详解JavaStream的sorted自定义排序》Javastream中的sorted方法是用于对流中的元素进行排序的方法,它可以接受一个comparator参数,用于指定排序规则,sorte... 目录一、sorted 操作的基础原理二、自定义排序的实现方式1. Comparator 接口的 Lam

Android DataBinding 与 MVVM使用详解

《AndroidDataBinding与MVVM使用详解》本文介绍AndroidDataBinding库,其通过绑定UI组件与数据源实现自动更新,支持双向绑定和逻辑运算,减少模板代码,结合MV... 目录一、DataBinding 核心概念二、配置与基础使用1. 启用 DataBinding 2. 基础布局

Android ViewBinding使用流程

《AndroidViewBinding使用流程》AndroidViewBinding是Jetpack组件,替代findViewById,提供类型安全、空安全和编译时检查,代码简洁且性能优化,相比Da... 目录一、核心概念二、ViewBinding优点三、使用流程1. 启用 ViewBinding (模块级

如何自定义一个log适配器starter

《如何自定义一个log适配器starter》:本文主要介绍如何自定义一个log适配器starter的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求Starter 项目目录结构pom.XML 配置LogInitializer实现MDCInterceptor

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

Druid连接池实现自定义数据库密码加解密功能

《Druid连接池实现自定义数据库密码加解密功能》在现代应用开发中,数据安全是至关重要的,本文将介绍如何在​​Druid​​连接池中实现自定义的数据库密码加解密功能,有需要的小伙伴可以参考一下... 目录1. 环境准备2. 密码加密算法的选择3. 自定义 ​​DruidDataSource​​ 的密码解密3