基于Android 的 自定义半圆进度条

发布时间:2020-09-22
技术:java+databinding+viewmodel

概述

该项目主要是自定义半圆进度条,可通过配置文件修改开口大小,前置色,底色,左右图标和显示状态等等,同时也运用了viewmodel 和databinding 技术,用MVVM架构模式来实现效果

详细

一、项目结构

├─app

│  ├─libs

│  └─src

│      ├─main

│      │  ├─java

│      │  │  └─com

│      │  │      └─sky

│      │  │          └─customviewforcircle

│      │  │              ├─activity

│      │  │              ├─utils

│      │  │              ├─viewmodel

│      │  │              └─widget

│      │  └─res

│      │      ├─drawable

│      │      ├─drawable-v24

│      │      ├─drawable-xxhdpi

│      │      ├─layout

│      │      ├─mipmap-anydpi-v26

│      │      ├─mipmap-hdpi

│      │      ├─mipmap-mdpi

│      │      ├─mipmap-xhdpi

│      │      ├─mipmap-xxhdpi

│      │      ├─mipmap-xxxhdpi

│      │      └─values

│      └─test

│          └─java

│              └─com

│                  └─sky

│                      └─customviewforcircle

└─gradle

    └─wrapper


二、程序实现

1、工程目录

project.png


2、在layout 中的布局

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="vm"
            type="com.sky.customviewforcircle.viewmodel.ProgressBarViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:gravity="center"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="自定义半圆形进度条"
                android:textColor="@color/pink"
                android:textSize="@dimen/sp_20" />

        </LinearLayout>

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/dp_50"
            android:background="@drawable/vi">

            <com.sky.customviewforcircle.widget.CustomerProgressBar
                android:id="@+id/progressbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:layout_marginLeft="@dimen/dp_40"
                android:layout_marginRight="@dimen/dp_40"
                app:angel="3"
                app:front_color="@color/pink"
                app:progress="0"
                app:show_left_icon="false"
                app:show_right_icon="true" />

            <TextView
                android:id="@+id/tv_progress"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:gravity="center"
                android:textSize="40sp" />
        </FrameLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/dp_50"
            android:orientation="horizontal">

            <Button
                android:id="@+id/bt_add"
                android:layout_width="0dp"
                android:layout_height="50dp"
                android:layout_weight="1"
                android:onClick="@{(v)->vm.plusMethod(v)}"
                android:text="+" />

            <Button
                android:id="@+id/bt_subtract"
                android:layout_width="0dp"
                android:layout_height="50dp"
                android:layout_weight="1"
                android:onClick="@{(v)->vm.subtraction(v)}"
                android:text="-" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/dp_80"
                android:gravity="center_vertical"
                android:orientation="horizontal">

                <EditText
                    android:layout_width="0dp"
                    android:layout_height="50dp"
                    android:layout_weight="3"
                    android:background="@color/color_white"
                    android:hint="请输入进度条数据"
                    android:inputType="numberDecimal"
                    android:paddingLeft="@dimen/dp_15"
                    android:textColor="@color/pink"
                    android:textSize="@dimen/sp_18"
                    app:addTextChangedListener="@{vm.textWatcher}" />

                <TextView
                    android:layout_width="0dp"
                    android:layout_height="@dimen/dp_50"
                    android:layout_weight="1"
                    android:background="@color/pink"
                    android:gravity="center"
                    android:onClick="@{(v)->vm.setProgress(v)}"
                    android:text="确定"
                    android:textColor="@color/color_white"
                    android:textSize="@dimen/sp_16" />


            </LinearLayout>

            <View
                android:layout_width="match_parent"
                android:layout_height="0.5dp"
                android:background="#E0E0E0" />
        </LinearLayout>
    </LinearLayout>
</layout>





2、自定义view核心代码


 1)获取配置参数

public CustomerProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    mContext = context;
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.custom, defStyleAttr, 0);
    floatAngel = a.getFloat(R.styleable.custom_angel, 2);
    frontColor = a.getColor(R.styleable.custom_front_color, 
    context.getResources().getColor(R.color.color_white));
    bottomColor = a.getColor(R.styleable.custom_back_color, 
    context.getResources().getColor(R.color.color_white4D));
    aimPercent = a.getFloat(R.styleable.custom_progress, 0);
    leftBitmap = BitmapFactory.decodeResource(context.getResources(), 
    a.getResourceId(R.styleable.custom_left_icon, R.drawable.golden_crown));
    rightBitmap = BitmapFactory.decodeResource(context.getResources(), 
    a.getResourceId(R.styleable.custom_right_icon, R.drawable.golden_diamond));
    isShowRightIcon = a.getBoolean(R.styleable.custom_show_right_icon, false);
    isShowLeftIcon = a.getBoolean(R.styleable.custom_show_left_icon, false);
    isShowCurrentPoint = a.getBoolean(R.styleable.custom_show_current_point, true);
    a.recycle();
    initView(context);

}


2)根据进度条数据创建画布

private void drawInsideView(float formDegree, float toDegree, Canvas canvas, 
               int color, float startDegree, float endDegree) {
    shaderPaint.setStrokeWidth(insideArcWidth);
    shaderPaint.setStyle(Paint.Style.STROKE);
    insideArea = new RectF(width/2 - insideArcRadius, radius-insideArcRadius, width/2
    + insideArcRadius, radius + insideArcRadius);
    canvas.drawArc(insideArea, formDegree, toDegree, false, shaderPaint);

    if (toDegree != 0) {
       if (isShowCurrentPoint) {
          Path orbit = new Path();
          orbit.addArc(insideArea, formDegree, toDegree);
          PathMeasure measure = new PathMeasure(orbit, false);
          measure.getPosTan(measure.getLength() * 1, pos, tan);
          mMatrix.reset();
          mMatrix.postTranslate(pos[0] - mBitmapPoint.getWidth() / 2, 
                                pos[1] - mBitmapPoint.getHeight() / 2);
          canvas.drawPath(orbit, shaderPaint);
          canvas.drawBitmap(mBitmapPoint, mMatrix, bitmapPaint);
          bitmapPaint.setColor(color);
          canvas.drawCircle(pos[0], pos[1], 30, bitmapPaint);
        }
    }

    if (isShowLeftIcon) {
        Path startorbit = new Path();
        startorbit.addArc(insideArea, formDegree, startDegree);
        createImgeView(startorbit, canvas, leftBitmap);
    }
    if (isShowRightIcon) {
        Path endOrBit = new Path();
        Bitmap endBitmap = rightBitmap;
        endOrBit.addArc(insideArea, formDegree, endDegree);
        createImgeView(endOrBit, canvas, endBitmap);
    }
}


3)实现 onDraw方法

(Canvas canvas) {
    onDraw(canvas)= getWidth()= / + ScreenUtil. paintPercentBack(canvas)drawPercent(canvas)}

三、实现逻辑

  主要是自定义view的思想,结合画布用来实现

     1、 先测量高度,控件的高度是又半圆开口到顶端的距离,就是高度

     2、重写onDraw方法,在这个方法里面,根据配置参数,判断是否要显示左右两边的图标,然后画底色,              顶部颜色,还有根据坐标点画大圆和小圆,最后在画布上渲染,完成最后的工作

     3、可通过动态设置进度条值和进度条前置颜色来满足需求

        

四、运行效果

1、可在布局设定默认进度值,同时可用+ - 按钮进行加减操作

image.png


2、也可以在输入框输入进度值

image.png

本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码