我的第一個自定義View

直接上代碼,做個學習筆記好了。

/**
 * Created by Jimbray  .
 * on 2016/7/12
 * Email: jimbray16@gmail.com
 * Description: 這是我第一個真正意義上的自定義View
 */
public class MyFirstProgressbar extends View {

    //max progress 雖然注釋寫了,但是還是不解釋
    private int mMaxProgress = 100;

    // current progress
    private int mCurrentProgress;

    //progress bar 背景顏色
    private int mBackgroundColor;

    //progress bar 進度條顏色
    private int mProgressColor;

    //progress bar 進度條高度
    private float mProgressBarheight;

    //progress bar 背景高度
    private float mBackgroundHeight;

    //設置默認值
    //默認progress bar 背景顏色
    private final int default_background_color = Color.rgb(204, 204, 204);
    //默認progress bar 進度條顏色
    private final int default_progressbar_color = Color.rgb(66, 145, 241);
    //默認 pregress bar 背景高度
    private float default_background_height;
    //默認 porgress 進度條高度
    private float default_progressbar_height;
    //默認progress bar 背景寬度(最小寬度)
    private final float default_background_width = dp2px(45.f);

    //畫筆
    private Paint mBackgroundPaint, mProgressbarPaint;

    //progress 需要draw 的矩形區域
    private RectF mBackgroundRectF = new RectF(0, 0, 0, 0);
    private RectF mProgressbarRectF = new RectF(0, 0, 0, 0);


    public MyFirstProgressbar(Context context) {
        super(context);
        init(context, null, 0);
    }

    public MyFirstProgressbar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0);
    }

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

    }

    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        default_background_height = dp2px(1.0f);
        default_progressbar_height = dp2px(1.5f);
        //progress bar 背景高度 比 progress bar 進度條高度 矮啊

        //都是用默認值,沒有把這些數值拋出去做屬性
        mBackgroundHeight = default_background_height;
        mProgressBarheight = default_progressbar_height;

        mBackgroundColor = default_background_color;
        mProgressColor = default_progressbar_color;

        initPainters();
    }

    /**
     * 初始化 畫筆 Paint
     */
    private void initPainters() {
        mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBackgroundPaint.setColor(mBackgroundColor);

        mProgressbarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mProgressbarPaint.setColor(mProgressColor);
    }

    /**
     * 重載 函數
     * @return view 的推薦最小寬度
     * 修改為 progress bar 背景的默認高度
     */
    @Override
    protected int getSuggestedMinimumWidth() {
        return (int) default_background_width;
    }

    /**
     * 重載 函數
     * @return view 的推薦最小高度
     * 修改為 progress bar 的默認高度 (娶個最高的吧,不然高的那個頭被截掉了就不好了)
     */
    @Override
    protected int getSuggestedMinimumHeight() {
        return Math.max((int) mBackgroundHeight, (int) mProgressBarheight);
    }

    /**
     * 這個函數的 解析 Google 一大把,就不解釋了
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     * 現在這里是個套路活,跟著老司機走就行了
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measure(widthMeasureSpec, true), measure(heightMeasureSpec, false));
    }

    /**
     * 測量 view 的 寬高信息
     * @param measureSpec
     * @param isWidth
     * @return
     */
    private int measure(int measureSpec, boolean isWidth) {
        int result;
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);
        //不要忘記 padding ,萬一有人設置了呢
        int padding = isWidth ? getPaddingLeft() + getPaddingRight() : getPaddingTop() + getPaddingBottom();
        if (mode == MeasureSpec.EXACTLY) { //如果 width 或者 height 都設置了 精確值:比如 45dp啊什么的
            result = size; //就按主人的來吧,誒,森么是主人
        } else {
            //其他情況,既然你都不知道要什么,就按我的套路來吧
            result = isWidth ? getSuggestedMinimumWidth() : getSuggestedMinimumHeight();
            result += padding; //padding 這個小伙子還是很調皮的
            if (mode == MeasureSpec.AT_MOST) {
                if (isWidth) {
                    result = Math.max(result, size);
                } else {
                    result = Math.min(result, size);
                }
            }
        }
        return result;
    }

    /** 要開車了,快上車!
     * @param canvas
     */
    @Override
    protected synchronized void onDraw(Canvas canvas) {
        calRectF();

        canvas.drawRect(mBackgroundRectF, mBackgroundPaint);

        canvas.drawRect(mProgressbarRectF, mProgressbarPaint);
    }

    /**
     * 精華就在這里了。
     * 一開始我也看不懂
     * 現在我也看不懂
     * 可是效果出來了
     * 就這么滴吧
     * 多看幾次
     * 說不定就懂了呢
     */
    private void calRectF() {
        mProgressbarRectF.left = getPaddingLeft();
        mProgressbarRectF.top = getHeight() / 2.0f - mProgressBarheight / 2.0f;
        mProgressbarRectF.right = (getWidth() - getPaddingLeft() - getPaddingRight()) / (getMax() * 1.0f) * getProgress() + getPaddingLeft();
        mProgressbarRectF.bottom = getHeight() / 2.0f + mProgressBarheight / 2.0f ;

        mBackgroundRectF.left = mProgressbarRectF.right;
        mBackgroundRectF.top = getHeight() / 2.0f - mBackgroundHeight / 2.0f;
        mBackgroundRectF.right = getWidth() - getPaddingRight();
        mBackgroundRectF.bottom = getHeight() / 2.0f + mBackgroundHeight / 2.0f;

    }

    /** 這個我也不想說
     * 如果三個月之后我看不懂這個代碼
     * 說明
     * 我應該是失憶了
     * @return
     */
    public int getProgress() {
        return mCurrentProgress;
    }

    /**
     * 同上
     * @return
     */
    public int getMax() {
        return mMaxProgress;
    }

    /**
     * 同上
     * @param progress
     */
    public void setProgress(int progress) {
        mCurrentProgress = progress;
        invalidate();
    }

    /**
     * 讓我的 progress 動起來!
     * ValueAnimator 是個神器
     * Google一下
     * @param progress
     */
    public void anitProgress(int progress) {
        ValueAnimator animator = ValueAnimator.ofInt(0, progress);
        animator.setDuration(1500);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mCurrentProgress = (int) animation.getAnimatedValue();
                postInvalidate();
            }
        });

        animator.start();
    }

    public float dp2px(float dp) {
        final float scale = getResources().getDisplayMetrics().density;
        return dp * scale + 0.5f;
    }

這就是我第一個實質意義上的自定義View了,以前一般都是擴展TextView啊,組合LinearLayout
之類的。
雖然這個View也是看著別人的代碼寫的。
不過總算是自己動手敲出來了。
敲開心啊。
照抄學習的 project 代碼家NumberProgressBar
已發布到

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,595評論 25 708
  • 國內自定義View的文章汗牛充棟,但是,即便是你全部看完也未必掌握這一知識(實際上,我也看了很多,但是一旦涉及自定...
    SnowDragonYY閱讀 1,654評論 3 36
  • 國內自定義View的文章汗牛充棟,但是,即使你全部看完它們也未必能掌握這一知識點(實際上,我就幾乎看完了所有的國內...
    工程師milter閱讀 37,821評論 143 673
  • 地處安丘西南大約一百里的石埠子鎮(原庵上鎮,為什么要提庵上呢?后續會有庵上鎮的故事的)有座本地很有名的文化名山——...
    天涯行者閱讀 3,168評論 0 3
  • 手和嘴不協調,手緊緊握住小饅頭,嘴也用勁張的,手抓著小饅頭已經送到嘴邊,正常應該是松手嘴就吃上了,可是實際上寶寶手...
    宸宸的楠楠媽媽閱讀 582評論 0 0