android之自定义view和ViewGroup(三)(代码篇,实现条形进度条)

由于重新理了理博客,所以将此篇更改了下作为自定义的代码篇,如果不懂自定义View的原理和实现步骤的可以先看看android之自定义View和ViewGroup(一),具体解释不就不废话了,前面那个链接上写的很清楚了,此篇直接来代码实现。

假如我们需要实现的效果是这样(模拟器有点卡,见谅):


那么我们可以分析下,需要什么思路,由于图片问题,图中可能不明显,结构是这样的:

三层,一层红色背景,一层内层粉色,再是一个绿色进度的方形条,那么我们就画一个方形红色背景,在里面再画一个粉色方形,然后里面再画一个绿色的方形进行移动,但是移动范围是粉色框内,思路就是这样,那么开始

我们自定义view就需要几个属性:

1.背景色(图中红色)

2.内部背景色(图中粉色)

3.进度方块的颜色(图中绿色)

4.红色框的线的宽度(因为我画的是一个没有填充满颜色的红色框,只是画的一个带红色stroke的框,可以根据自己的想法更改)

那么自定义一共要三个模块:

1.在attrs中自定义需要的属性(上面4个)

2.继承View自定义View进行画进度条的逻辑

3.在xml布局中使用


我们先来第一个模块:

(1)在attrs中自定义需要的属性(如果没有attrs.xml就在res/values下建个就行)

<attr name="backColor" format="color"/>
    <attr name="progressColor" format="color"/>
    <attr name="strokeColor" format="color"/>
    <attr name="strokeWidth" format="dimension"/>
    <declare-styleable name="CustomprogressBarView">
        <attr name="strokeWidth"/>
        <attr name="backColor"/>
        <attr name="progressColor"/>
        <attr name="strokeColor"/>
    </declare-styleable>
我们自定义出了4个需要的属性,name表示引用名,format表示值的类型,

(2)继承View自定义View进行画进度条的逻辑实现,写CustomProgressbar继承自View,然后重写它的ondraw方法

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.custom.my.R;

/**
 * Created by Administrator on 2016/1/14.
 */
public class CustomProgressbar extends View {
    private int backColor;  //图中粉色
    private int progressColor;  //图中绿色
    private int strokeColor;  //图中红色

    private Paint paintBack;  //粉色对应的画笔
    private Paint paintProgress;  //绿色对应的画笔
    private Paint paintStroke;  //红色对应的画笔

    private int progress = 1;  //代表进度快(将图中粉色分为30块,那么进度条的方式就是从第一块移动到第二块,第三块。。。最后一块,回到第一块),可以自定义
    private int num = 30;  //粉色分为多少块,这里设为30块,如果需要自定义也可以,这里就直接这样吧
    private float averageWidth;  //平均宽度
    private float strokeWidth;  //红色的宽度

    private Handler handler = new Handler();
    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            postInvalidate();  //刷新view
            progress ++;
            if(progress == num+1){
                progress = 1;
            }
            handler.postDelayed(this,100); //每隔100ms就移动一次(比如粉色分为30块,绿色在第一块,然后100ms后移动到第二块,第三块。。。等)
        }
    };

    public CustomProgressbar(Context context) {
        this(context,null);
    }

    public CustomProgressbar(Context context, AttributeSet attrs) {
        this(context,attrs,0);
    }

    public CustomProgressbar(Context context, AttributeSet attrs, int defStyleAttr) {  //构造方法不用说了吧
        super(context, attrs, defStyleAttr);
        TypedArray arr = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomprogressBarView, defStyleAttr, 0);  //获取自定义的属性值组
        backColor = arr.getColor(R.styleable.CustomprogressBarView_backColor, Color.WHITE);  //获取自定义的属性backColor,默认为白色
        progressColor = arr.getColor(R.styleable.CustomprogressBarView_progressColor, Color.RED);  //获取自定义的属性progressColor,默认为红色
        strokeColor = arr.getColor(R.styleable.CustomprogressBarView_strokeColor, Color.GRAY);  //获取自定义的属性,外框的颜色即图中的红色框
        strokeWidth = arr.getDimensionPixelSize(R.styleable.CustomprogressBarView_strokeWidth, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, getResources().getDisplayMetrics()));  //获取自定义的设置线条框宽度的属性,默认为15sp
        arr.recycle();  //用完后记得recycle();
        paintBack = new Paint(); 
        paintProgress = new Paint();
        paintStroke = new Paint();
        handler.postDelayed(runnable,100);  //使用handler实现定时更新操作
    }  

    @Override
    protected void onDraw(Canvas canvas) {  //重写onDraw来画进度条
        int width = getWidth();  //获取自定义的View的宽度
        int height = getHeight();  //获取自定义的View的高度

	//设置红色框画笔属性,宽度和颜色,描边效果
        paintStroke.setColor(strokeColor); 
        paintStroke.setStrokeWidth(strokeWidth);
        paintStroke.setDither(true);
        paintStroke.setStyle(Paint.Style.STROKE);
        canvas.drawRect(strokeWidth / 2, strokeWidth / 2, width - strokeWidth / 2, height - strokeWidth / 2, paintStroke);  //画红色矩形框,参数是:左上右下位置和画笔
	//设置粉色框的画笔属性
        paintBack.setColor(backColor);
        paintBack.setDither(true);
        canvas.drawRect(strokeWidth, strokeWidth, width-strokeWidth, height-strokeWidth, paintBack);//画粉色矩形框,参数同上

        float contentWidth = width - strokeWidth*2;  //这里画绿色进度条框,需要计算宽了,因为我们分成了30块,横向滑动,绿色块的活动范围是粉色框,粉色框宽度是总宽度减去左右2根红色线条的宽度
        averageWidth = contentWidth/30;  //绿色进度框的宽度
	//绿色进度框的画笔属性
        paintProgress.setColor(progressColor);
        paintProgress.setDither(true);
        canvas.drawRect((progress - 1) * averageWidth + strokeWidth, strokeWidth, progress * averageWidth + strokeWidth, height - strokeWidth, paintProgress);  //根据progress记录绿色框移动到粉色的30块中的哪一块,然后在对应的位置画下绿色框
    }
}


(3)在xml布局中使用

记得加入命名空间:图中绿色代码,或者:xmlns:xjj="http://schemas.android.com/apk/res-auto",这个xjj可以自定义,定义后,代码中引用属性的时候就要用这个,即下面的红色代码

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:xjj="http://schemas.android.com/apk/res/com.custom.my"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.custom.my.activity.CustomProgressActivity">

    <com.custom.my.view.CustomProgressbar
        android:layout_centerInParent="true"
        xjj:backColor="#50ff0000"
        xjj:strokeWidth = "1dp"
        xjj:strokeColor = "#50ff00ff"
        xjj:progressColor = "#00ffaa"
        android:layout_width="100dp"
        android:layout_height="5dp" />

</RelativeLayout>

然后这样就完成了进度条的自定义效果,执行就行了 ,有什么不懂得可以问我。

对了,如果看了android之自定义View和ViewGroup(一)的人可能会问了,不是说要重写onMeasure方法测量大小么?测量大小也是需要分情况的,比如自定义这个进度条,必须给一个固定的宽高值,不然设置成wrap_content也不知改设置多大啊。当然你可以设置为wrap_content然后在onMeasure方法里面测量的时候如果是wrap_content就给他一个默认的宽高之类的;由于咋们使用这个进度条肯定是给定了具体的宽高,所以就不需要根据测量模式进行测量了,因为给了固定宽高,那么默认测量的结果就是固定宽高的结果,结果正确。只有在没有设置固定宽高的时候需要测量,比如自定义ImageView那种,设置为wrap_content就需要测量了,此时ImageView的宽高需要设为图片的宽和高才正确。而这个进度条这个你根本不知道内容宽高,所以设为具体值合理又方便。


发布了33 篇原创文章 · 获赞 49 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/gsw333/article/details/50803313