Android自定义view实现圆形进度条效果
作者:吐尔洪江Coding 发布时间:2021-09-12 00:30:03
标签:Android,view,进度条
Android中实现进度条有很多种方式,自定义进度条一般是继承progressBar或继承view来实现,本篇中讲解的是第二种方式。
先上效果图:
实现圆形进度条总体来说并不难,还是跟往常一样继承view,初始化画笔,按下面的步骤一步步来就好了。对初学者来说动画效果可能比较陌生,我们可以使用属性动画中的valueAnimator来实现动画效果。
实现步骤:
1、画出一个灰色的圆环作为背景。
2、画出上层的圆环覆盖下方的圆环。
3、加入动画效果
值得注意的是怎么设置圆环和文字的位置。
画出矩形只需要传入矩形对角线的坐标即可,如果不加以处理的话画出来的圆环的边缘是不完整的,刚开始接触自定义view的同学们一定要先好好看看Android坐标系相关内容,不然很难理解位置参数为什么这样设置。
完整代码:
package com.example.floatingwindow.widget;
?
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
?
import androidx.annotation.Nullable;
?
import com.example.floatingwindow.R;
?
public class ProgressBarView extends View {
?
? ? private Paint mPaintBack;
? ? private Paint mPaint;
? ? private Paint mPaintText;
? ? private float process;
? ? private int strokeWidth = 15;
? ? private int textSize = 20;
? ? private long duration = 3000;
? ? private float startDegree = 0;
? ? private float endDegree = 360;
? ? private String text = "完成";
? ? private String defaultText = "0%";
?
?
? ? public ProgressBarView(Context context) {
? ? ? ? super(context);
? ? ? ? init();
? ? }
?
? ? public ProgressBarView(Context context, @Nullable AttributeSet attrs) {
? ? ? ? super(context, attrs);
? ? ? ? init();
? ? }
?
? ? public ProgressBarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
? ? ? ? super(context, attrs, defStyleAttr);
? ? ? ? init();
? ? }
?
? ? private void init() {
? ? ? ? mPaintBack = new Paint();
? ? ? ? mPaintBack.setColor(getResources().getColor(R.color.gray));
? ? ? ? mPaintBack.setStyle(Paint.Style.STROKE);
? ? ? ? mPaintBack.setAntiAlias(true);
? ? ? ? mPaintBack.setStrokeCap(Paint.Cap.ROUND);
? ? ? ? mPaintBack.setStrokeWidth(strokeWidth);
?
? ? ? ? mPaint = new Paint();
? ? ? ? mPaint.setColor(getResources().getColor(R.color.purple_200));
? ? ? ? mPaint.setStyle(Paint.Style.STROKE);
? ? ? ? mPaint.setAntiAlias(true);
? ? ? ? mPaint.setStrokeCap(Paint.Cap.ROUND);
? ? ? ? mPaint.setStrokeWidth(strokeWidth);
?
? ? ? ? mPaintText = new Paint();
? ? ? ? mPaintText.setAntiAlias(true);
? ? ? ? mPaintText.setStyle(Paint.Style.STROKE);
? ? ? ? mPaintText.setColor(Color.BLACK);
? ? ? ? mPaintBack.setStrokeCap(Paint.Cap.ROUND);
? ? ? ? mPaintText.setTextSize(sp2px(textSize));
? ? }
?
? ? public void setStrokeWidth(int width) {
? ? ? ? strokeWidth = width;
? ? }
?
? ? public void setTextSize(int textSize) {
? ? ? ? this.textSize = textSize;
? ? }
?
? ? public void setDuration(long duration) {
? ? ? ? this.duration = duration;
? ? }
?
? ? @Override
? ? protected void onDraw(Canvas canvas) {
? ? ? ? super.onDraw(canvas);
? ? ? ? //创建圆环矩形
? ? ? ? RectF rectF = new RectF(strokeWidth, strokeWidth, getWidth() - strokeWidth, getHeight() - strokeWidth);
? ? ? ? //画出灰色进度条作为背景
? ? ? ? canvas.drawArc(rectF, 0, 360, false, mPaintBack);
? ? ? ? //画进度条
? ? ? ? canvas.drawArc(rectF, 0, process, false, mPaint);
? ? ? ? //计算进度
? ? ? ? int percent = (int) (process / 360 * 100);
? ? ? ? //设置文字在canvas中的位置
? ? ? ? Paint.FontMetrics fm = mPaintText.getFontMetrics();
? ? ? ? int mTxtWidth = (int) mPaintText.measureText(text, 0, defaultText.length());
? ? ? ? int mTxtHeight = (int) Math.ceil(fm.descent - fm.ascent);
? ? ? ? int x = getWidth() / 2 - mTxtWidth / 2;
? ? ? ? int y = getHeight() / 2 + mTxtHeight / 4;
? ? ? ? if (percent < 100) {
? ? ? ? ? ? canvas.drawText(percent + "%", x, y, mPaintText);
? ? ? ? } else {
? ? ? ? ? ? canvas.drawText(text, x, y, mPaintText);
? ? ? ? }
? ? }
?
? ? /**
? ? ?* 设置动画效果
? ? ?*/
? ? public void start() {
? ? ? ? ValueAnimator valueAnimator = ValueAnimator.ofFloat(startDegree, endDegree);
? ? ? ? valueAnimator.setDuration(duration);
? ? ? ? valueAnimator.setInterpolator(new DecelerateInterpolator());
? ? ? ? valueAnimator.addUpdateListener(animation -> {
? ? ? ? ? ? process = (float) animation.getAnimatedValue();
? ? ? ? ? ? invalidate();
? ? ? ? });
? ? ? ? valueAnimator.start();
? ? }
?
? ? private int sp2px(int sp) {
? ? ? ? return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,
? ? ? ? ? ? ? ? getResources().getDisplayMetrics());
? ? }
}
最后就是动画效果了,使用valueanimator,传入开始和结束的进度以及执行时间。然后每次进度发生变化时做UI刷新。
xml布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
? ? xmlns:app="http://schemas.android.com/apk/res-auto"
? ? xmlns:tools="http://schemas.android.com/tools"
? ? android:layout_width="match_parent"
? ? android:layout_height="match_parent"
? ? tools:context=".MainActivity">
?
? ? <com.example.floatingwindow.widget.ProgressBarView
? ? ? ? android:id="@+id/progressBar"
? ? ? ? android:layout_width="150dp"
? ? ? ? android:layout_height="150dp"
? ? ? ? app:layout_constraintTop_toTopOf="parent"
? ? ? ? app:layout_constraintBottom_toBottomOf="parent"
? ? ? ? app:layout_constraintStart_toStartOf="parent"
? ? ? ? app:layout_constraintEnd_toEndOf="parent">
? ? </com.example.floatingwindow.widget.ProgressBarView>
?
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity:
class MainActivity : AppCompatActivity() {
? ? override fun onCreate(savedInstanceState: Bundle?) {
? ? ? ? super.onCreate(savedInstanceState)
? ? ? ? setContentView(R.layout.activity_main)
?
? ? ? ? progressBar.start()
?
? ? ? ? progressBar.setOnClickListener { progressBar.start()}
? ? }
来源:https://blog.csdn.net/daydayup05/article/details/122150161
0
投稿
猜你喜欢
- 看到这个sweet-alert-dialog很亲切,因为前端开发本人用的提示就是这个js插件,java牛人很厉害,直接弄成一个java包插件
- 在使用feign调用其它服务时,发现获取的参数是null,当参数是对象是,是执行的Post请求,所以要在方法参数前加@RequestBody
- 概述LruCache的核心原理就是对LinkedHashMap的有效利用,它的内部存在一个LinkedHashMap成员变量,值得注意的4个
- 本文实例为大家分享了Java操作qq邮箱发送邮件的具体代码,供大家参考,具体内容如下今天尝试了使用QQ邮箱的POP3/IMAP/SMTP/E
- 实现客户端发送请求,服务器端响应机制UDP客户端代码using System;using System.Text;using System.
- 就是每隔一定的时间显示一张图片,全部图片文件位于:“工作空间\项目名称\bin\动态图\花好月圆\”文件夹下。文件名类似:1001.jpg,
- JWT可以理解为一个加密的字符串,里面由三部分组成:头部(Header)、负载(Payload)、签名(signature)由base64加
- 本文描述了TCP协议,首先简单介绍了TCP完成了一些什么功能;介绍了TCP报文格式,以及典型报文的数据格式;接着从链路控制和数据传输两个方面
- 责任链模式责任链模式的定义:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系, 将这个对象连成一条链,并沿着这条链传递
- 本文实例讲述了C#创建、读取和修改Excel的方法。分享给大家供大家参考。具体如下:windows下我们可以通过 Jet OLE DB访问E
- 前言 ChatGPT已经组件放开了,现在都可以基于它写插件了。但是说实话我还真没想到可以用它干嘛,也许
- 本篇内容主要讲述了实现基于微软账户的第三方身份验证、实现双因子身份验证、 验证码机制这3个内容。实现基于微软账户的第三方身份验证在
- 这个小代码是我凭自己对指针和链表的理解和认识,自己实现的,没有参考其他人的代码,如果有相同的地方,那真的只是巧合,代码我在ubuntu 15
- 目录Fanout交换机模型RabbitMQ控制台操作新增两个队列绑定fanout交换机示例效果图核心代码消息发布消息订阅Fanout交换机模
- 如何将Object类型转换为int类型Object object = null;try{ Integer.pars
- WPF实现一个简单的多运算符表达式计算器,供大家参考,具体内容如下1.先看下效果图首先外围给了一个grid 把他分成了两行 第一行用来显示文
- 本文实例讲述了Android编程实现左右滑动切换背景的方法。分享给大家供大家参考,具体如下:最近想做一个左右滑动切换背景图片的应用,特地将自
- 导读Spring Boot应用可以使用spring-boot-maven-plugin快速打包,构建一个可执行jar。Spring Boot
- 什么是栈和队列栈如果用数组模拟的话是类似于一个U形桶状堆栈空间,地下是封口的,只能从顶部一个地方进出,它的进出都是有顺序的,看下图:如果是进
- 根据不同系统动态获取换行符和盘分割符1、获取盘分割符File.separator2、获取换行符windows系统为\r\n,Linux系统为