带进度条的控件--CircleProcessView
CircleProcessView
package com.example.myapplication.demoUI;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewGroup;
import androidx.appcompat.widget.AppCompatImageView;
import com.example.myapplication.R;
/**
* 1.初始化画笔,测量
* 2.确定位置绘制图形
* 3.处理点击事件
* 4.编写接口,暴露方法给外部
*/
public class PausePressView extends AppCompatImageView {
private Paint circlePaint;
private int defaultWidth, defaultHeight;
public PausePressView(Context context) {
this(context, null);
}
public PausePressView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PausePressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint();
setPadding(20, 20, 20, 20);
}
@SuppressLint("ResourceAsColor")
private void initPaint() {
circlePaint = new Paint();
circlePaint.setColor(getContext().getResources().getColor(R.color.c_FF6E66));
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setAntiAlias(true);
circlePaint.setStrokeCap(Paint.Cap.ROUND);//笔帽
circlePaint.setStrokeWidth(5);
}
/*
* 测量模式 ** 视图的赋值方式 ** 描述
* UNSPECIFIED ** MATCH_PARENT ** 与上一级视图大小一样
* AT_MOST ** WRAP_CONTENT ** 包裹其自身内容(按照自身尺寸进行适配)
* EXACTLY ** 整型数值 ** 设置尺寸的数值
*
* //获取父 View 的测量模式
* int specMode = MeasureSpec.getMode(measureSpec);
* //获取父 View 的测量尺寸
* int specSize = MeasureSpec.getSize(measureSpec);
* */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
ViewGroup.LayoutParams layoutParams = this.getLayoutParams();
if (layoutParams != null) {
defaultHeight = layoutParams.height;
defaultWidth = layoutParams.width;
}
//获取到图片资源的大小,然后设置大小
setMeasuredDimension(defaultWidth, defaultHeight);
}
//换算 测量控件宽、高
private int de_width = 20, de_height = 20;
protected int measureDimension(int defaultSize, int measureSpec) {
int result = defaultSize;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
//1. layout给出了确定的值,比如:100dp
//2. layout使用的是match_parent,但父控件的size已经可以确定了,
// 比如设置的是具体的值或者match_parent
if (specMode == MeasureSpec.EXACTLY) {
result = specSize; //建议:result直接使用确定值
}
//1. layout使用的是wrap_content
//2. layout使用的是match_parent,但父控件使用的是确定的值或者wrap_content
else if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(defaultSize, specSize); //建议:result不能大于specSize
}
//UNSPECIFIED,没有任何限制,所以可以设置任何大小
//多半出现在自定义的父控件的情况下,期望由自定义自行决定大小
else {
result = defaultSize;
}
return result;
}
RectF rect;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
if (rect == null) {
rect = new RectF(10, 10, measuredWidth - 10, measuredHeight - 10);
}
circlePaint.setColor(getContext().getResources().getColor(R.color.c_FFE7E6));
//绘制底线
canvas.drawArc(rect, -90, 360, false, circlePaint);
circlePaint.setColor(getContext().getResources().getColor(R.color.c_FF6E66));
//绘制前景线
canvas.drawArc(rect, -90, currentProgress, false, circlePaint);
}
//倒计时的时长
private int countDownDuration = 2;
//当前的进度
private float currentProgress = 0;
//手是否有释放
private boolean isRelease = false;
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
//start
this.isRelease = false;
this.setImageResource(R.drawable.zuye_yinyue_bofan_d);
startCountDown();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
//end
this.isRelease = true;
//告诉外部
if (currentProgress < 360 && mOnCountDownStateChangeListener != null) {
mOnCountDownStateChangeListener.onCountDownCancel();
}
break;
}
//消费掉此事件
return true;
}
private void startCountDown() {
if (this.currentProgress >= 360) {
this.currentProgress = 0;
}
//换算成毫秒
int duration;
if (!isRelease) {
duration = countDownDuration * 1000;
} else {
//往回倒时只要1秒的动画即可
duration = 1000;
}
//第20毫秒绘制一次进度
int rate = duration / 20;
//求度数
float perDegree = 360 * 1.0f / rate;
//The runnable will be run on the user interface thread.
post(new Runnable() {
@Override
public void run() {
if (!isRelease) {
currentProgress += perDegree;
} else {
currentProgress -= perDegree;
}
if (currentProgress < 0) {
currentProgress = 0;
}
if (currentProgress >= 360) {
//结束了
currentProgress = 360;
//TODO:告诉外部
if (mOnCountDownStateChangeListener != null) {
mOnCountDownStateChangeListener.onCountDownEnd();
}
}
//重新绘制
invalidate();
if (currentProgress > 0 && currentProgress < 360) {
postDelayed(this, 20);
}
}
});
}
private OnCountDownStateChangeListener mOnCountDownStateChangeListener;
//定义接口 暴露方法
public interface OnCountDownStateChangeListener{
//end
void onCountDownEnd();
//cancel
void onCountDownCancel();
}
public void setOnCountDownStateChangeListener(OnCountDownStateChangeListener listener) {
this.mOnCountDownStateChangeListener = listener;
}
}
分类:
Android
, Android-自定义控件-学习记录
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!