android自定义view实现进度条动画、按钮渐变及录制状态控制

    技术2025-06-04  26

    不得不说自定义view绘制各种图形及它们的动画是令人有成就感的事情。该篇来分享之前项目中写的一个视频录制按钮的自定义view,该view有录制、暂停(结束)等状态的控制,各种状态转变的动画,以及录制进度展示。先看效果(圆圈的小白色段是最小录制时长的标记点): 代码的内容其实主要就是绘制进度条、录制按钮的切换动画(圆角正方形—>圆—>圆角正方形)。还是那句话,计算好每个组件的坐标(半径)事情就完成了一半,所以关键在于计算,这里的图形都简单计算并不复杂,只是要稍微细心点。注释都写得比较详细,就不一一解释了,具体看代码:

    import android.content.Context; import android.graphics.Canvas; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.Shader; import android.util.AttributeSet; import android.view.View; import androidx.annotation.Nullable; import com.robot.common.frame.BaseApp; import com.robot.common.utils.PixelUtil; /** * 视频录制控制、进度 * * @author ly * date 2020/3/3 11:02 */ public class RecordProgressView extends View implements View.OnClickListener { private static final float changeRatio = 5f; //最小录制时长标记的弧长 private static final int minPAngle = 2; private OnRecordStatusListener onRecordStatusListener; private Paint paint; //内圈录制、暂停按钮颜色 private int circleInsideColor; //进度圈颜色 private int circleOutsideColor; //进度颜色 private int circleProgressColor; private float progressW; //进度条圆圈半径 private float circleProgressR; //内实心圆圈半径 private float circleInsideR; //录制按钮宽高 private float pauseRectW; //动态变量内圈半径(逐渐变小或变大) private float curCircleInsideR; private State state = State.READY; //暂停按钮rect private RectF pauseRect; private int pauseRadius; private RectF progressRect; private float progress; private float minProgress = 90; private float minCircleR; private LinearGradient linearGradientCircle; private LinearGradient linearGradientRect; public enum State { READY, RECORDING, PAUSE, FINISH } public RecordProgressView(Context context) { super(context); init(); } public RecordProgressView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public RecordProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { circleInsideColor = 0xffE9B763; circleOutsideColor = 0x55ffffff; circleProgressColor = 0xffffffff; paint = new Paint(); paint.setAntiAlias(true);//抗锯齿 pauseRadius = PixelUtil.dp2px(5); setOnClickListener(); } public float getProgress() { return progress; } /** * @param progress 已录制时长/最大时长 * @author ly on 2020/3/3 16:41 */ public void setProgress(float progress) { this.progress = progress * 360; if (this.progress >= 360) {//表示录制达到最大时长,自动结束 this.progress = 360; state = State.FINISH; if (onRecordStatusListener != null) onRecordStatusListener.onFinish(); } invalidate(); } /** * @param minProgress 最小录制时长/最大时长 * @author ly on 2020/3/3 16:41 */ public void setMinProgress(float minProgress) { this.minProgress = minProgress * 360; } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (circleProgressR == 0) { int w = getWidth(); progressW = w * 0.061f; circleProgressR = (w - progressW) / 2f; circleInsideR = (w * 0.83f) / 2; pauseRectW = w * 0.37f; curCircleInsideR = circleInsideR; //矩形对角线的一半 // minCircleR = (float) (Math.sqrt(Math.pow(pauseRectW, 2) * 2) / 2f); minCircleR = pauseRectW / 2; pauseRect = new RectF(w / 2f - pauseRectW / 2 , w / 2f - pauseRectW / 2 , w / 2f + pauseRectW / 2 , w / 2f + pauseRectW / 2); progressRect = new RectF(0 + progressW / 2, 0 + progressW / 2, w - progressW / 2, w - progressW / 2); float offsetX = (float) Math.sqrt(Math.pow(curCircleInsideR, 2) / 2); //圆的左上到右下方向渐变 linearGradientCircle = new LinearGradient( curCircleInsideR - offsetX, curCircleInsideR - offsetX, w - offsetX, w - offsetX, 0xff7360FF, 0xff9663F3, Shader.TileMode.MIRROR); linearGradientRect = new LinearGradient( pauseRect.left, pauseRect.top, pauseRect.right, pauseRect.bottom, 0xff7360FF, 0xff9663F3, Shader.TileMode.MIRROR); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //画外圈进度圈、进度 paint.setShader(null); paint.setStyle(Paint.Style.STROKE); paint.setColor(circleOutsideColor); paint.setStrokeWidth(progressW);//设置画笔粗细 canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, circleProgressR, paint); if (minProgress - minPAngle > 0 && BaseApp.get().isDebug()) { paint.setColor(circleProgressColor); canvas.drawArc(progressRect, minProgress - 90, minPAngle, false, paint); } if (state != State.READY) { //进度就是圆弧 //时钟3点的方向为0度,顺时钟方向为正,-90是圆弧的开始点,即12点位置开始, //sweepAngle扫过的角度,调整该值即可实现进度顺时针加载(0-360) paint.setColor(circleProgressColor); canvas.drawArc(progressRect, -90, progress, false, paint); } //画内部圆/暂停按钮 paint.setColor(circleInsideColor); paint.setStyle(Paint.Style.FILL); paint.setShader(linearGradientCircle); if (state == State.RECORDING) {//录制中画矩形和进度 if (curCircleInsideR > minCircleR) { canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, curCircleInsideR, paint); changeCircleR(false); } else { paint.setShader(linearGradientRect); canvas.drawRoundRect(pauseRect, pauseRadius, pauseRadius, paint); } } else { canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, curCircleInsideR, paint); if (curCircleInsideR < circleInsideR) changeCircleR(true); } } public void resetState() { state = State.READY; progress = 0; invalidate(); } public void setState(State state) { this.state = state; invalidate(); } public void setOnClickListener() { setOnClickListener(this); } @Override public void onClick(View v) { switch (state) { //由开始状态变为录制状态,点击后由圆变为矩形 case READY: case PAUSE: state = State.RECORDING; if (onRecordStatusListener != null) onRecordStatusListener.onRecording(); invalidate(); break; //录制中,点击后由矩形变为圆 case RECORDING: if (progress < minProgress) { state = State.PAUSE; if (onRecordStatusListener != null) onRecordStatusListener.onPause(); } else { state = State.FINISH; if (onRecordStatusListener != null) onRecordStatusListener.onFinish(); } invalidate(); break; default: break; } } private void changeCircleR(boolean is2Big) { if (is2Big) {//变大 curCircleInsideR += changeRatio; if (curCircleInsideR >= circleInsideR) curCircleInsideR = circleInsideR; } else {//变小 curCircleInsideR -= changeRatio; if (curCircleInsideR <= minCircleR) curCircleInsideR = minCircleR; } invalidate(); } public void setOnRecordStatusListener(OnRecordStatusListener onRecordStatusListener) { this.onRecordStatusListener = onRecordStatusListener; } public interface OnRecordStatusListener { void onRecording(); void onPause(); void onFinish(); } }

    如果对大家有帮助,请点个赞以鼓励我前进~

    Processed: 0.010, SQL: 9