文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android自定义圆环计时器——史上最详细篇

2022-06-06 14:13

关注

自定义的圆环计时器提供了以下属性

          
          
          
          
          
          
          
代码与注释
package com.example.view;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;
import androidx.annotation.Nullable;
import com.example.binder.R;
public class TimerCircle extends View {
    //圆环画笔
    private Paint mPaint;
    //圆画笔
    private Paint nPaint;
    //1.圆的颜色
    private int circle_color;
    //2.圆环颜色
    private int ring_color;
    //3.圆环大小对应着画笔的宽度
    private int ring_width;
    //4.指定控件宽度和长度
    private int width;
    private int height;
    //50.字体颜色
    private int text_color;
    //51.字体大小
    private int text_size;
    //52.路径颜色
    private int path_color;
    //5.通过宽度和高度计算得出圆的半径
    private int radius;
    //6.指定动画的当前值,比如指定动画从0-10000。
    private int current_value;
    //7.进行到x秒时,对应的圆弧弧度为 x/ * 360.f x可以currentValue得出 currentValue/1000代表秒
    private float  angle_value;//圆弧角度
    //8.通过valueAnimator我们可以获得currentValue
    private ValueAnimator animator;
    //9.表示valueAnimator的持续时间,这里设置为和最大倒计时时间相同
    private float duration;
    //10.最大倒计时时间,如果1分钟计时,这里就有600000ms,单位是ms
    private int maxTime=10000;
    //这里设置为10是为了避免  angleValue = currentValue/maxTime*360.0f除数为0的异常,如果既没有在xml中设置最大值就会报错,这是由绘制流程决定的。
    //11.当前的时间是指倒计时剩余时间,需要显示在圆中
    private int currentTime;
    private onFinishListener finishListenter;
    public TimerCircle(Context context) {
        this(context,null);//12.TimerCircle circle = new TimerCircle()时调用该构造方法
    }
    public TimerCircle(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);//13.通过xml使用自定义View时使用该构造方法
    }
    public TimerCircle(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);//14.一般不会主动调用该方法,除非手动指定调用。
        //15.获取属性
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TimerCircle);
        circle_color = typedArray.getColor(R.styleable.TimerCircle_circleColor, Color.BLUE);
        ring_color = typedArray.getInteger(R.styleable.TimerCircle_ringColor, 0);
        ring_width = (int) typedArray.getDimension(R.styleable.TimerCircle_width, getResources().getDimension(R.dimen.width));
        text_color = typedArray.getColor(R.styleable.TimerCircle_path, Color.RED);
        text_size = (int) typedArray.getDimension(R.styleable.TimerCircle_textSize,getResources().getDimension(R.dimen.textSize));
        path_color = typedArray.getColor(R.styleable.TimerCircle_path, Color.RED);
        typedArray.recycle();
        InitPaint();
    }
    private void InitPaint() {
        mPaint = new Paint();
        mPaint.setColor(ring_color);
        mPaint.setAntiAlias(true);
        nPaint = new Paint();
        nPaint.setAntiAlias(true);
        nPaint.setColor(circle_color);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //16.如果padding和wrap-content失效,还要在这里处理
        int widthPixels = this.getResources().getDisplayMetrics().widthPixels;//17. 获取屏幕宽度
        int heightPixels = this.getResources().getDisplayMetrics().heightPixels;//18.获取屏幕高度
        //19.测量,目的是为了根据指定的宽高和屏幕的宽高最终确定圆的半径,四个中最小的即为半径
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        int minWidth = Math.min(width, widthPixels);
        int minHeight = Math.min(height, heightPixels);
        setMeasuredDimension(Math.min(minHeight, minWidth), Math.min(minHeight, minWidth));
    }
    @Override
    protected void onDraw(Canvas canvas) {
        //20.确定内圆的半径
        int in_radius = (this.getWidth()-2*ring_width)/2;
        //21.确定圆的圆心
        int center = this.getWidth()-in_radius-ring_width;
        //22.绘制内圆和圆环
        drawInner(canvas, in_radius,center);
        //23.绘制倒计时的字体
        drawText(canvas,center);
    }
    private void drawInner(Canvas canvas, int radius, int center) {
        //24.先画出内圆
        canvas.drawCircle(center, center, radius, nPaint);
        //25.画圆环,设置为空心圆,指定半径为内圆的半径,画笔的宽度就是圆环的宽度
        mPaint.setStyle(Paint.Style.STROKE);//26.设置空心圆
        mPaint.setStrokeWidth(ring_width);//27.画笔宽度即圆环宽度
        mPaint.setColor(ring_color);//28. 圆环的颜色
        canvas.drawCircle(center, center, radius, mPaint);
         //30.内圆的外接矩形,有什么作用?绘制圆弧时根据外接矩形绘制
        RectF rectF = new RectF(center-radius,center-radius,center+radius,center+radius);
        //31.计算弧度,通过当前的currentValue的值得到
        angle_value = current_value * 360.0f / maxTime * 1.0f;
        //32.设置阴影大小和颜色
        mPaint.setShadowLayer(10, 10, 10, Color.BLUE);
        //33.指定线帽样式,可以理解为一条有宽度的直线的两端是带有弧度的
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        //34.圆弧的颜色
        mPaint.setColor(path_color);
        //35.绘制圆弧
        canvas.drawArc(rectF, -90,angle_value , false, mPaint);
    }
    public void setDuration(int duration, final int maxTime) {
        //36.如果外部指定了最大倒计时的时间,则xml定义的最大倒计时无效,以外部设置的为准
        this.maxTime=maxTime;
        //37.持续时间和最大时间保持一致,方便计算
        this.duration=duration;
        if (animator != null) {
            animator.cancel();
        } else {
            animator = ValueAnimator.ofInt(0, maxTime);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    //38.获取此时的进度
                    current_value = (int) animation.getAnimatedValue();
                    if(current_value==maxTime){
                        finishListenter.onFinish();
                    }
                    //39.invalidate()方法系统会自动调用 View的onDraw()方法。
                    invalidate();
                }
            });
            //40.线性插值器,匀速变化
            animator.setInterpolator(new LinearInterpolator());
        }
        animator.setDuration(duration);
        animator.start();
    }
    private void drawText(Canvas canvas,int center) {
        //41.计算当前的剩余的时间,单位s
        currentTime=(maxTime-current_value)/1000;
        //42.显示的倒计时字符串
        String Text=null;
        if(currentTime=10&&currentTime60&&currentTime<600){
            int min = currentTime/60;
            int sen = currentTime%60;
            if (sen<10) {
                Text="0"+min+":0"+sen;
            }else{
                Text="0"+min+":"+sen;
            }
        }else{
            int min = currentTime/60;
            int sen = currentTime%60;
            if (sen<10) {
                Text=min+":0"+sen;
            }else{
                Text=min+":"+sen;
            }
        }
        // 43.设置文字居中,以左下角为基准的(x,y)就是这里的center baseline。具体的关于drawText需要查看https://blog.csdn.net/harvic880925/article/details/50423762/
        mPaint.setTextAlign(Paint.Align.CENTER);
        // 44.设置文字颜色
        mPaint.setColor(text_color);
        mPaint.setTextSize(text_size);
        mPaint.setStrokeWidth(0);//清除画笔宽度
        mPaint.clearShadowLayer();//清除阴影
        // 45.文字边框
        Rect bounds = new Rect();
        // 46.获得绘制文字的边界矩形
        mPaint.getTextBounds(Text, 0, Text.length(), bounds);
        // 47.获取绘制Text时的四条线
        Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
        // 48.计算文字的基线
        int baseline = center - (fontMetrics.bottom+fontMetrics.top)/2;
        // 49.绘制表示进度的文字
        canvas.drawText(Text, center, baseline, mPaint);
    }
    public interface onFinishListener{
       void onFinish();
    }
    public void setFinishListenter(onFinishListener listenter){
        this.finishListenter = listenter;
    }
}
使用
 

具体不多说了,注释非常清楚了,请看效果图
原创文章 153获赞 128访问量 5万+ 关注 私信 展开阅读全文
作者:༺ IF ༻


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯