Android 自定義View——帶下載進度Button

之前看到某些應用商店的下載按鈕帶下載進度提示,感覺很實用,自己也試着簡單地實現這個功能。下面是效果圖

這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述

在attrs.xml添加下載進度按鈕所需的自定義屬性

 <declare-styleable name="DownLoadButton">
        <attr name="normalBackground" format="reference|color"/>
        <attr name="downLoadedBackground" format="reference|color"/>
        <attr name="downLoadCompleteBackground" format="reference|color"/>
        <attr name="textColor" format="reference|color"/>
    </declare-styleable>

自定義下載進度按鈕的代碼

 /**
 * Created by 犀利的小牛 on 2016/8/8.
 */
public class DownLoadButton extends Button {

    private Paint paint;
    /**
     * 文本顏色
     */
    private int textColor;
    /**
     * 未下載狀態背景
     */
    private Drawable normalBackground;
    /**
     * 已下載進度背景
     */
    private Drawable downLoadBackground;
    /**
     * 下載完成背景
     */
    private Drawable completeBackground;
    /**
     * 未下載狀態
     */
    public final static int STATE_NORMAL = 0;
    /**
     * 下載中
     */
    public final static int STATE_DOWNLOADING = 1;
    /**
     * 下載完成
     */
    public final static int STATE_COMPLETE = 2;

    /**
     * 當前狀態
     */
    private int curState = 0;
    /**
     * 當前下載進度
     * 百分比
     */
    private int curPrecent = 0;

    private OnDownLoadButtonClickListener onDownLoadButtonClickListener;

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

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

    public DownLoadButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DownLoadButton, defStyleAttr, 0);
        normalBackground = getResources().getDrawable(R.drawable.rect_normal_bg);
        downLoadBackground = getResources().getDrawable(R.drawable.rect_downloaded_bg);
        completeBackground = getResources().getDrawable(R.drawable.rect_complete_bg);

        final int N = a.getIndexCount();
        for (int i = 0; i < N; i++) {
            int attr = a.getIndex(i);
            switch (attr) {
                case R.styleable.DownLoadButton_normalBackground:
                    normalBackground = a.getDrawable(attr);
                    break;
                case R.styleable.DownLoadButton_downLoadedBackground:
                    downLoadBackground = a.getDrawable(attr);
                    break;
                case R.styleable.DownLoadButton_downLoadCompleteBackground:
                    completeBackground = a.getDrawable(attr);
                    break;
                case R.styleable.DownLoadButton_textColor:
                    textColor = a.getColor(attr, getResources().getColor(R.color.color_white));
                    break;
            }
        }
        /**
         * 設置button本身的文字爲透明以免干擾我們自己繪製上去的文字
         */
        setTextColor(getResources().getColor(R.color.color_transparent));
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setTextSize(getTextSize());
        paint.setColor(textColor);

        curState = STATE_NORMAL;
        setGravity(Gravity.CENTER);

        /**
         * 設置點擊事件
         *   這個方法行得通,但是我感覺有更好的實現方式。
         */
        setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (onDownLoadButtonClickListener != null) {
                    //點擊時返回當前的狀態
                    onDownLoadButtonClickListener.onClick(v, curState);
                }
            }
        });
    }

    /**
     * 設置當前狀態
     *
     * @param state
     */
    public void setState(int state) {
        this.curState = state;
        postInvalidate();
    }

    /**
     * 設置下載進度
     *
     * @param precent
     *        完成進度百分比
     */
    public void setDownLoadProgress(int precent) {
        this.curPrecent = precent;
        postInvalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width = 0;
        int height = 0;
        /**
         * 計算文本顯示所需寬高
         */
        Rect textBound = new Rect();
        String tip = getResources().getString(R.string.download_complete);
        paint.getTextBounds("下載完成", 0, tip.length(), textBound);

        if(widthMode == MeasureSpec.EXACTLY){
            width = widthSize+getPaddingLeft()+getPaddingRight();
        }else{
            width = textBound.width()+getPaddingLeft()+getPaddingRight();
        }

        if(heightMode == MeasureSpec.EXACTLY){
            height = heightSize+getPaddingTop()+getPaddingBottom();
        }else{
            height = textBound.height()+getPaddingTop()+getPaddingBottom();
        }

        setMeasuredDimension(width,height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        String tip = "";
        switch (curState) {
            case STATE_NORMAL:
                tip = getResources().getString(R.string.download);
                curPrecent = 0;
                setBackgroundDrawable(normalBackground);
                break;
            case STATE_DOWNLOADING:
                tip = curPrecent+"%";
                //計算當前進度所需寬度
                int downLoadedWidth = (int) (getMeasuredWidth() * ((double) curPrecent / 100));
                Rect rect = new Rect(0, 0, downLoadedWidth, getMeasuredHeight());
                downLoadBackground.setBounds(rect);
                downLoadBackground.draw(canvas);
                break;
            case STATE_COMPLETE:
                tip = getResources().getString(R.string.download_complete);
                setBackgroundDrawable(completeBackground);
                break;
        }
        /**
         * 繪製提示文本
         */
        Rect textBound = new Rect();
        paint.getTextBounds(tip, 0, tip.length(), textBound);
        canvas.drawText(tip,(getMeasuredWidth()-textBound.width())/2,(getMeasuredHeight()+textBound.height())/2, paint);
    }


    public void setOnDownLoadButtonClickListener(OnDownLoadButtonClickListener onDownLoadButtonClickListener) {
        this.onDownLoadButtonClickListener = onDownLoadButtonClickListener;

    }

    public interface OnDownLoadButtonClickListener {
        void onClick(View v, int curState);
    }

}  

MainActicity中的代碼很簡單,模擬下載過程

/**
 * Created by 犀利的小牛 on 2016/8/8.
 */
public class MainActivity extends AppCompatActivity implements DownLoadButton.OnDownLoadButtonClickListener {

    private DownLoadButton downLoadButton;
    private DownLoadHandler downLoadHandler;
    private final static int MESSAGE_DOWNLOADING = 0;
    private int downLoadedPrecent = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        downLoadHandler = new DownLoadHandler();

        downLoadButton = (DownLoadButton) findViewById(R.id.downLoadButton);
        downLoadButton.setOnDownLoadButtonClickListener(this);
    }

    @Override
    public void onClick(View v, int curState) {
        if (curState == DownLoadButton.STATE_NORMAL) {
            //開始下載
            downLoadButton.setState(DownLoadButton.STATE_DOWNLOADING);
            downLoadHandler.sendEmptyMessageDelayed(MESSAGE_DOWNLOADING,2000);
        }else if(curState == DownLoadButton.STATE_DOWNLOADING){
            //下載中如果被點擊時停止下載,這裏可以根據自個的需求換成暫停或者其他
            downLoadButton.setState(DownLoadButton.STATE_NORMAL);
            downLoadedPrecent = 0;
            downLoadHandler.removeMessages(MESSAGE_DOWNLOADING);
        }
    }

    private class DownLoadHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MESSAGE_DOWNLOADING:
                    //模擬下載
                    downLoadedPrecent+=10;
                    if(downLoadedPrecent>=100){
                        downLoadButton.setState(DownLoadButton.STATE_COMPLETE);
                    }else{
                        downLoadButton.setDownLoadProgress(downLoadedPrecent);
                        sendEmptyMessageDelayed(MESSAGE_DOWNLOADING,2000);
                    }
                    break;
            }
        }
    }
}

最後是佈局的代碼

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="10dp"
    android:orientation="horizontal">

    <com.xiaoniu.downloadbuttom.DownLoadButton
        android:id="@+id/downLoadButton"
        android:layout_width="120dp"
        android:layout_height="80px"
        android:textColor="@android:color/white"
        app:normalBackground="@drawable/rect_normal_bg"
        app:downLoadedBackground="@drawable/rect_downloaded_bg"
        app:downLoadCompleteBackground="@drawable/rect_downloaded_bg"
        android:textSize="20sp"
        app:textColor="@color/color_white"
        />

</LinearLayout>

————————————————————————

源碼地址

發佈了32 篇原創文章 · 獲贊 111 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章