美文网首页
android自定义view圆形百分比progressBar√

android自定义view圆形百分比progressBar√

作者: 码仔时光 | 来源:发表于2020-07-04 15:54 被阅读0次

    前言

    最近工作太不饱和,基本是这个节奏:
    8.40到公司,吃个早餐,边吃边玩手机
    9.消化一下,打开电脑看会新闻。****(这一段被屏蔽了,印度和香港问题不能写?),哎,我大清太难了
    9.30-10.带薪拉屎时间
    10.如果当天有茅台抢购,也是要打开京东抢一抢的,虽然东哥暂时还不认我这个兄弟
    11.要开始做点事了(反正不是工作的事)
    12.-1.30吃饭、午觉
    14.把每个群的消息浏览一遍,最活跃的群非同学们的炒股群莫属(每天如此),都在讨论牛市要来了,准备进场一把梭哈。我也想试试,但是奈何钱不够,今天还要交房租。
    15.要开始做点事了(一般是逛知乎、写博客)
    16.下半场休息时间,这个时候一般抽根黄鹤楼斗斗地主,豆子很快就会输完,好在我有两个号,想骗我充值、看广告,不存在的
    17.继续做“事”
    18.准点下班(怪不好意思的)

    h5、小程序开发倒是挺忙的,过几天要正儿八经学一下小程序,希望能一起帮前端的兄弟一起迭代之前的小程序。
    现在呢,时间总不能浪费,写写blog吧,记录一下,说不定还能帮到需要的朋友。

    进入正题,继续接着上一篇android自定义view实现进度条动画、按钮渐变及录制状态控制
    ,趁热打铁,继续来画个进度条,这个跟上一篇实现方式类似,多了一个百分比数字显示以及完成后的√。

    上效果:

    在这里插入图片描述

    没什么好解释的,直接上代码:

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Path;
    import android.graphics.RectF;
    import android.text.TextUtils;
    import android.util.AttributeSet;
    import android.view.View;
    import androidx.annotation.Nullable;
    
    /**
     * 进度
     *
     * @author ly
     * date 2020/3/3 11:02
     */
    public class CircleProgressView extends View {
    
        private static final int COMPLETE = 360;
        private int okSpeed = 3;
    
        private Paint paint;
        //进度圈颜色
        private int circleOutsideColor;
        //进度颜色
        private int circleProgressColor;
        private float progressW;
        //进度条圆圈半径
        private float circleProgressR;
        private OnProgressListener onProgressListener;
    
        private RectF progressRect;
        private float progress;
        private String progressText;
        private Path okPath;
        private int sX, sY;
        private int mX;
        private int eX;
        private int cX, cY;
    
        public CircleProgressView(Context context) {
            super(context);
            init();
        }
    
        public CircleProgressView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        public CircleProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        private void init() {
            circleOutsideColor = 0xffF2F4F5;
            circleProgressColor = 0xff6066DD;
            paint = new Paint();
            paint.setAntiAlias(true);//抗锯齿
            paint.setDither(true); //设置防抖动
        }
    
        /**
         * @param progress 已加载进度/总进度
         * @author ly on 2020/3/3 16:41
         */
        public void setProgress(float progress) {
            this.progress = progress * COMPLETE;
            if (this.progress >= COMPLETE) {//表示录制达到最大时长,自动结束
                this.progress = COMPLETE;
            }
            progressText = (int) (progress * 100) + "%";
            invalidate();
        }
    
        public void reset() {
            setProgress(0);
    
        }
    
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            super.onLayout(changed, left, top, right, bottom);
            if (circleProgressR == 0 || okPath == null) {
                int w = getWidth();
                progressW = w * 0.061f;
                circleProgressR = (w - progressW) / 2f;
    
                progressRect = new RectF(0 + progressW / 2, 0 + progressW / 2, w - progressW / 2, w - progressW / 2);
    
                int okW = (int) ((getWidth() - progressW) * 0.45);
                int okH = (int) ((getHeight() - progressW) * 0.32);
    
                cX = sX = (getWidth() - okW) / 2;
                cY = sY = getHeight() / 2;
                mX = (int) (sX + 0.39 * okW);
                int mY = (int) (sY + 0.35 * okW);
                eX = getWidth() - (getWidth() - okW) / 2;
                int eY = (getHeight() - okH) / 2;
    
                okPath = new Path();
                okPath.moveTo(sX, sY);
            }
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //画进度圈
            paint.setStyle(Paint.Style.STROKE);
            paint.setColor(circleOutsideColor);
            paint.setStrokeWidth(progressW);//设置画笔粗细
            canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, circleProgressR, paint);
    
            //画进度就是圆弧
            //时钟3点的方向为0度,顺时钟方向为正,-90是圆弧的开始点,即12点位置开始,
            //sweepAngle扫过的角度,调整该值即可实现进度顺时针加载(0-360)
            paint.setColor(circleProgressColor);
            canvas.drawArc(progressRect, -90, progress, false, paint);
    
            if (progress < COMPLETE) {
                if (!TextUtils.isEmpty(progressText)) {
                    // 将坐标原点移到控件中心
                    int dx = getWidth() / 2;
                    int dy = getHeight() / 2;
                    canvas.translate(dx, dy);
                    // 绘制居中文字
                    paint.setTextSize(PixelUtil.sp2px(30));
                    // 文字宽
                    float textWidth = paint.measureText(progressText);
                    // 文字baseline在y轴方向的位置
                    float baseLineY = Math.abs(paint.ascent() + paint.descent()) / 2;
                    paint.setStyle(Paint.Style.FILL);
    //            paint.setStrokeWidth(2);
                    canvas.drawText(progressText, -textWidth / 2, baseLineY, paint);
                }
            } else {//加载完成,画√
                if (cX < eX) {//来个动画凑合用
                    cX += okSpeed;
                    if (cX < mX) {
                        cY += okSpeed;
                    } else {
                        cY -= okSpeed;
                    }
                    invalidate();
                } else {
                    postDelayed(() -> {
                        if (onProgressListener != null)
                            onProgressListener.complete();
                    }, 1500);
                }
                okPath.lineTo(cX, cY);
                canvas.drawPath(okPath, paint);
            }
        }
    
        public float getProgress() {
            return progress / COMPLETE;
        }
    
        public void setOnProgressListener(OnProgressListener onProgressListener) {
            this.onProgressListener = onProgressListener;
        }
    
        public interface OnProgressListener {
            void complete();
        }
    }
    
    

    还是说一下那个√的动画吧,其实是个规则的图形,都是直线。x轴的坐标是增加的,y坐标先递减再递增。由于要画的√的两条直线可拆分为两个等腰三角形对应的斜边,所以x和y坐标的增减量(okSpeed)都相等。这里有两个优化点:
    1、okSpeed的值是固定的,可添加插值器来改变okSpeed的值,从而达到画√的速率
    2、这个√的开始和结束的两端是直角,略生硬,可优化成圆角(画笔设置paint.setStrokeCap(Paint.Cap.ROUND)即可)
    其他没什么好说的,上dialog的代码:

    import android.content.Context;
    import android.view.Gravity;
    import android.view.View;
    import android.widget.ImageView;
    import android.widget.TextView;
    import androidx.annotation.NonNull;
    
    /**
     * @author ly
     * date 2019/8/1 17:36
     */
    public class CircleProgressDialog extends BaseDialog {
    
        private CircleProgressView circleProgressView;
        private TextView tv_dialog_progress_status;
        private ImageView iv_dialog_progress_close;
        private OnProgressCallBack onProgressCallBack;
    
        public CircleProgressDialog(@NonNull Context context, OnProgressCallBack onProgressCallBack) {
            super(context);
            this.onProgressCallBack = onProgressCallBack;
    
        }
    
        @Override
        public int getLayoutResId() {
            return R.layout.v_dialog_circle_progress;
        }
    
        @Override
        public void initViews() {
            if (getWindow() != null) {
                getWindow().getAttributes().width = ScreenUtil.getScreenWidth() * 4 / 5;
                getWindow().setGravity(Gravity.CENTER);
            }
            setCanceledOnTouchOutside(false);
            setCancelable(false);
    
            circleProgressView = findViewById(R.id.circleProgressView);
            tv_dialog_progress_status = findViewById(R.id.tv_dialog_progress_status);
            iv_dialog_progress_close = findViewById(R.id.iv_dialog_progress_close);
            iv_dialog_progress_close.setOnClickListener(v -> {
                if (onProgressCallBack != null)
                    onProgressCallBack.intoNextPage();
                dismiss();
            });
            iv_dialog_progress_close.setVisibility(View.GONE);
    
            circleProgressView.setOnProgressListener(() -> {
                if (onProgressCallBack != null)
                    onProgressCallBack.intoNextPage();
                dismiss();
            });
            setOnDismissListener(dialog -> circleProgressView.reset());
        }
    
        public void setProgress(float progress) {
            circleProgressView.setProgress(progress);
            if (progress >= 1) {
                tv_dialog_progress_status.setText("发布成功");
                iv_dialog_progress_close.setVisibility(View.VISIBLE);
            } else {
                tv_dialog_progress_status.setText("正在发布中...");
                iv_dialog_progress_close.setVisibility(View.GONE);
            }
        }
    
        public float getProgress() {
            return circleProgressView.getProgress();
        }
    
        public interface OnProgressCallBack {
            void intoNextPage();
        }
    }
    

    v_dialog_circle_progress:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:background="@drawable/shape_white_r16"
        android:padding="12dp">
    
        <ImageView
            android:id="@+id/iv_dialog_progress_close"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:src="@mipmap/ico_close4dialog" />
    
    
        <com.xxx.CircleProgressView
            android:id="@+id/circleProgressView"
            android:layout_width="117dp"
            android:layout_height="117dp"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="34dp" />
    
        <TextView
            android:id="@+id/tv_dialog_progress_status"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/circleProgressView"
            android:layout_centerHorizontal="true"
            android:paddingTop="23dp"
            android:paddingBottom="28dp"
            android:textColor="#ff727a7c"
            android:textSize="15sp"
            tools:text="正在发布中..." />
    </RelativeLayout>
    

    最后给个fake进度,就可以看到效果啦:

       private ScheduledFuture<?> scheduledFuture;
       private void fakeProgress() {
            CircleProgressDialog circleProgressDialog = new CircleProgressDialog(this, () -> {});
            circleProgressDialog.show();
            scheduledFuture = ExecutorServiceManager.get().getExecutorService().scheduleWithFixedDelay(() -> {
                runOnUiThread(() -> {
                    float progress = circleProgressDialog.getProgress();
                    if (!circleProgressDialog.isShowing() || videoNoteInfo != null) {
                        if (scheduledFuture != null)
                            scheduledFuture.cancel(true);
                        scheduledFuture = null;
                        return;
                    }
                    progress += 0.006f;
                    circleProgressDialog.setProgress(progress);
                });
            }, 0, 20, TimeUnit.MILLISECONDS);
        }
    

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

    end

    相关文章

      网友评论

          本文标题:android自定义view圆形百分比progressBar√

          本文链接:https://www.haomeiwen.com/subject/iymuqktx.html