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的寬高需要設爲圖片的寬和高才正確。而這個進度條這個你根本不知道內容寬高,所以設爲具體值合理又方便。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章