如何在Android中使用Java实现带时间动画的半圆弧进度条?
嘿,这个半圆弧进度条的需求我之前做过好几个类似的,咱们用自定义View就能完美实现,还能加上流畅的动画效果~下面一步步来拆解实现过程:
实现思路概述
核心思路是自定义View,通过Canvas绘制背景半圆弧和进度半圆弧,再用ValueAnimator驱动进度值的平滑变化,从而实现动画效果。具体分为这几步:
- 初始化画笔和基础属性
- 测量View尺寸,确保半圆比例协调
- 绘制背景圆弧和进度圆弧
- 添加动画逻辑,驱动进度更新
自定义半圆弧进度条View
直接上Java代码,关键部分我会做注释说明:
import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; public class SemiCircleProgressBar extends View { // 背景圆弧画笔 private Paint bgPaint; // 进度圆弧画笔 private Paint progressPaint; // 圆弧所在的矩形区域 private RectF arcRect; // 圆弧宽度(默认30dp) private int arcWidth = 30; // 背景圆弧颜色(默认浅灰色) private int bgColor = 0xFFE0E0E0; // 进度圆弧颜色(默认蓝色) private int progressColor = 0xFF2196F3; // 当前进度(范围0-100) private float currentProgress = 0; // 目标进度 private float targetProgress = 0; public SemiCircleProgressBar(Context context) { super(context); init(); } public SemiCircleProgressBar(Context context, AttributeSet attrs) { super(context, attrs); init(); } public SemiCircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { // 初始化背景画笔:抗锯齿、描边样式、圆角端点 bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); bgPaint.setColor(bgColor); bgPaint.setStyle(Paint.Style.STROKE); bgPaint.setStrokeWidth(arcWidth); bgPaint.setStrokeCap(Paint.Cap.ROUND); // 初始化进度画笔,和背景画笔属性一致,只改颜色 progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); progressPaint.setColor(progressColor); progressPaint.setStyle(Paint.Style.STROKE); progressPaint.setStrokeWidth(arcWidth); progressPaint.setStrokeCap(Paint.Cap.ROUND); arcRect = new RectF(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 让View高度最多为宽度的一半,保证半圆比例协调 int width = MeasureSpec.getSize(widthMeasureSpec); int height = Math.min(MeasureSpec.getSize(heightMeasureSpec), width / 2); setMeasuredDimension(width, height); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // 计算圆弧矩形区域:留出圆弧宽度的一半,避免画笔超出View边界 float padding = arcWidth / 2f; // 把矩形高度设为View高度的2倍,让半圆的圆心在View底部中间,画出上半圆 arcRect.set(padding, padding, w - padding, h * 2 - padding); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 绘制背景半圆弧:从180度(左侧)开始,逆时针画180度(形成上半圆) canvas.drawArc(arcRect, 180, -180, false, bgPaint); // 根据当前进度计算进度圆弧的扫过角度 float sweepAngle = -180 * (currentProgress / 100f); // 绘制进度圆弧 canvas.drawArc(arcRect, 180, sweepAngle, false, progressPaint); } // 设置目标进度并启动动画 public void setProgressWithAnimation(float target) { // 限制进度在0-100之间 targetProgress = Math.max(0, Math.min(100, target)); // 创建值动画,从当前进度平滑过渡到目标进度 ValueAnimator animator = ValueAnimator.ofFloat(currentProgress, targetProgress); animator.setDuration(1500); // 动画时长1.5秒,可按需调整 animator.addUpdateListener(animation -> { currentProgress = (float) animation.getAnimatedValue(); invalidate(); // 刷新界面,触发重绘 }); animator.start(); } // 以下是自定义属性的Setter方法,方便外部修改样式 public void setArcWidth(int arcWidth) { this.arcWidth = arcWidth; bgPaint.setStrokeWidth(arcWidth); progressPaint.setStrokeWidth(arcWidth); invalidate(); } public void setBgColor(int bgColor) { this.bgColor = bgColor; bgPaint.setColor(bgColor); invalidate(); } public void setProgressColor(int progressColor) { this.progressColor = progressColor; progressPaint.setColor(progressColor); invalidate(); } }
在项目中使用这个View
1. 布局文件中添加View
在你的xml布局里引入自定义View(注意替换com.yourpackage为你的实际包名):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <com.yourpackage.SemiCircleProgressBar android:id="@+id/progressBar" android:layout_width="300dp" android:layout_height="150dp" android:layout_marginBottom="20dp"/> <Button android:id="@+id/btnStart" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="启动进度动画"/> </LinearLayout>
2. 在Activity中触发动画
在Activity里绑定View,点击按钮启动进度动画:
import android.os.Bundle; import android.view.View; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { private SemiCircleProgressBar progressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); progressBar = findViewById(R.id.progressBar); findViewById(R.id.btnStart).setOnClickListener(v -> { // 设置目标进度为75%,启动动画 progressBar.setProgressWithAnimation(75); }); } }
扩展优化建议
- 如果需要下半圆:修改
onDraw中的drawArc参数,背景圆弧用startAngle=0, sweepAngle=180,进度圆弧的sweepAngle=180*(currentProgress/100f),同时调整arcRect的高度设置即可。 - 添加进度文本:在
onDraw中用canvas.drawText绘制当前进度百分比,注意计算文本的位置居中。 - 自定义动画插值器:可以给ValueAnimator设置
animator.setInterpolator(new AccelerateDecelerateInterpolator()),让动画节奏更自然。
内容的提问来源于stack exchange,提问作者Abdur Rehman
相关产品推荐
相关产品推荐

