Android 自定义View——带下载进度Button

之前看到某些应用商店的下载按钮带下载进度提示,感觉很实用,自己也试着简单地实现这个功能。下面是效果图

Android 自定义View——带下载进度Button_第1张图片
Android 自定义View——带下载进度Button_第2张图片
Android 自定义View——带下载进度Button_第3张图片

在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;
            }
        }
    }
}

最后是布局的代码


<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>

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

源码地址

你可能感兴趣的:(自定义View)