我的第二個(gè)自定義View

自古以來曾雕,第一個(gè)總是搶走了所有的聚光燈。
怎么辦助被,我是第二個(gè)剖张。

據(jù)說有一個(gè)國(guó)際慣例,要真相
那就來吧


真相

看到了嗎揩环。
下邊那個(gè)圓環(huán)就是我們第二個(gè)主角啦搔弄。
上面那個(gè)是 傳說中的第一個(gè)。
沒辦法检盼,第二個(gè)不管再怎么好看也比不上 號(hào)稱第一的那位肯污。
這翘单,應(yīng)該是一個(gè)詛咒吨枉。


/**
 * Created by Jimbray  .
 * on 2016/7/13
 * Email: jimbray16@gmail.com
 * Description: 這是我第二個(gè)自定義View。
 * 第一個(gè)永遠(yuǎn)是被人銘記的哄芜,可是第二個(gè)呢
 * 問你一個(gè)問題:世界上最高的山峰是貌亭?
 * 答:當(dāng)然是珠穆朗瑪峰啦!
 * 那第二高的呢认臊?
 * 答:當(dāng)然是喬戈里峰啦圃庭!
 * -_- 你不按套路出牌啊,套路里你是不知道的失晴!
 */
public class MySecondProgressbar extends View {

    private Context mContext;

    // 準(zhǔn)備好畫圓環(huán)的矩形區(qū)域
    private RectF mRectF = new RectF(0, 0, 0, 0);
    // 準(zhǔn)備好畫文字的矩形區(qū)域
    private RectF mTextRrectF = new RectF(0, 0, 0, 0);

    // 握好畫筆啊剧腻,有三個(gè)頻段,還有一個(gè)文字
    private Paint mHeavyProgressPaint, mModerateProgressPaint, mLightProgressPaint, mTextPaint;

    // 默認(rèn)值設(shè)置
    private final float default_height  = dp2px(45);
    private final float default_width   = dp2px(45);
    private final int default_heavy_color = Color.rgb(255, 54, 102);
    private final int default_moderate_color = Color.rgb(255, 128, 97);
    private final int default_light_color = Color.rgb(8, 176, 242);
    private final int default_text_color = Color.rgb(0, 0, 0);
    private final float default_text_size = sp2px(14);
    private final float default_heavy_progress_width = dp2px(12);
    private final float defaule_moderate_progress_width = dp2px(12);
    private final float default_light_progress_width = dp2px(12);

    //三個(gè)頻段涂屁,三種顏色啊书在,還有一個(gè)是字體顏色
    private int mHeavyColor, mModerateColor, mLightColor, mTextColor;
    //畫的東西寬高,還是給個(gè)默認(rèn)值好了
    private float mViewHeight, mViewWidth;
    //我們畫的是圓環(huán)拆又,要多粗有多粗栏账,定海神針,啊不挡爵,定海神環(huán)
    private float mHeavyProgressWidth, mModerateProgressWidth, mLightProgresswidth;

    private boolean mIfDrawText; //是不是要畫一下中間的文字呢。還是 寫
    private String mCurrentDrawText; //畫的文字你得告訴我吧
    private float mTextSize; //字別太大茶鹃,會(huì)撐著
    private int mTextBaseLine; //這個(gè) 我是抄的

    private float mCircleOffset = dp2px(15); //人與人之間的距離不要太近,還是要有一定的安全距離艰亮。不然親上了怎么辦。

    private float mCurrentProgress; //這第二個(gè)自定義View還是一個(gè)progressbar
    private float mCurHeavy, mCurModerate, mCurLight; //三個(gè)頻段垃杖,三個(gè)單詞是突然想到的,不知道什么意思

    public enum MySecondProgressTextVisibility {// 跟第一個(gè)自定義View最大的不同就是 :名字
        Visible, Invisible
    }

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

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

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

    /**
     *
     * 不想解釋
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        this.mContext = context;

        mHeavyColor = default_heavy_color;
        mModerateColor = default_moderate_color;
        mLightColor = default_light_color;
        mTextColor = default_text_color;

        mViewWidth = default_width;
        mViewHeight = default_height;

        mTextSize = default_text_size;

        mHeavyProgressWidth = default_heavy_progress_width;
        mModerateProgressWidth = defaule_moderate_progress_width;
        mLightProgresswidth = default_light_progress_width;

        mIfDrawText = true;

        initPainters();
    }

    /**
     * 上顏料
     */
    private void initPainters() {
        mHeavyProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mHeavyProgressPaint.setColor(mHeavyColor);
        mHeavyProgressPaint.setStyle(Paint.Style.STROKE);
        mHeavyProgressPaint.setStrokeWidth(mHeavyProgressWidth);

        mModerateProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mModerateProgressPaint.setColor(mModerateColor);
        mModerateProgressPaint.setStyle(Paint.Style.STROKE);
        mModerateProgressPaint.setStrokeWidth(mModerateProgressWidth);

        mLightProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mLightProgressPaint.setColor(mLightColor);
        mLightProgressPaint.setStyle(Paint.Style.STROKE);
        mLightProgressPaint.setStrokeWidth(mLightProgresswidth);

        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setColor(mTextColor);
        mTextPaint.setTextAlign(Paint.Align.CENTER);
        mTextPaint.setTextSize(mTextSize);
    }

    /**
     * 最小寬度 由你定
     * 不定我來給個(gè)最小值吧
     * @return
     */
    @Override
    protected int getSuggestedMinimumWidth() {
        return (int) mViewWidth;
    }

    /**
     * 跟寬度一個(gè)意思
     * @return
     */
    @Override
    protected int getSuggestedMinimumHeight() {
        return (int) mViewHeight;
    }

    /**
     * @param canvas
     * 咱先分析一下
     * 要畫什么
     * 我要畫一個(gè)圓環(huán)
     * 圓環(huán)里面有三個(gè)頻段的顯示(不同顏色)
     * 這三個(gè)頻段呢伶棒,分別代表三個(gè)數(shù)值的占比關(guān)系
     * 中間放個(gè)文字吧肤无,不然太空
     * 好像就這樣
     */
    @Override
    protected void onDraw(Canvas canvas) {
        if(mIfDrawText) {
            calWithText();
        } else {
            calWithoutText();
        }

        //上面已經(jīng)把我們要畫的區(qū)域圈出來了
        //可以施展拳腳,不對(duì)骇钦,是畫筆了

        float heavy_sweep_angle = mCurHeavy / mCurrentProgress; //算一下占比
        heavy_sweep_angle = heavy_sweep_angle * 360; //占比最終還是要轉(zhuǎn)換成角度的宛渐,0.5的話就是180度
        if(mCurHeavy != 0) {
            //從上面12點(diǎn)鐘的位置開始,就是270啦眯搭,我不喜歡負(fù)數(shù)窥翩,掃過多大的角度呢
            canvas.drawArc(mRectF, 270, heavy_sweep_angle, false, mHeavyProgressPaint); //試試把false改為true玩一玩,順便把paint 的stroke屬性去掉鳞仙。有驚喜哦寇蚊!
        }

        //跟上面的意思差不多啦。
        float moderate_sweep_angle = mCurModerate / mCurrentProgress;
        moderate_sweep_angle = moderate_sweep_angle * 360;
        if(mCurModerate != 0) {
            canvas.drawArc(mRectF, 270 + heavy_sweep_angle, moderate_sweep_angle, false, mModerateProgressPaint);
        }

        //還是一樣的棍好。
        float light_sweep_angle = mCurLight / mCurrentProgress;
        light_sweep_angle = light_sweep_angle * 360;
        if(mCurLight != 0) {
            canvas.drawArc(mRectF, 270 + heavy_sweep_angle + moderate_sweep_angle, light_sweep_angle, false, mLightProgressPaint);
        }
        //上面已經(jīng)把圓環(huán)都畫完了

        //畫個(gè)原點(diǎn)仗岸,我是來確定我寫的字是不是在中間,不能我說在中間就是在中間是吧借笙。如果它不是在中間扒怖,我把它說成在中間,然后被你發(fā)現(xiàn)它不在中間业稼,那我不是很尷尬盗痒。
//        canvas.drawOval(getWidth() /2 - 1 , getHeight() / 2 - 1, getWidth() / 2 + 1, getHeight() / 2 + 1, mHeavyProgressPaint); //畫個(gè)圓點(diǎn),看看文字是不是居中的

        if(mIfDrawText) { //準(zhǔn)備書法

//            canvas.drawRect(mTextRrectF, mLightProgressPaint); //畫個(gè)矩形 把text 框起來 ,參照物
            //第一種
            //這個(gè)是不對(duì)的做法盼忌,我以為是寫在了中間
//            canvas.drawText(mCurrentDrawText, getWidth() / 2.0f, getHeight() / 2.0f + (mTextPaint.descent() + mTextPaint.ascent()), mTextPaint);

            //第二種
            // 后來我知道我錯(cuò)了积糯,所以我就將錯(cuò)就錯(cuò)掂墓,再錯(cuò)一次
//            float text_width = mTextPaint.measureText(mCurrentDrawText);
//            canvas.drawText(mCurrentDrawText, mTextRrectF.left + text_width/2.0f, mTextRrectF.bottom, mTextPaint);

            //第三種
            //又來了!快看我找到的解決方案:[等燈等燈](http://blog.csdn.net/hursing/article/details/18703599)
            canvas.drawText(mCurrentDrawText, mTextRrectF.centerX(), mTextBaseLine, mTextPaint);
        }

    }

    /**
     * 精華1
     * 這里不寫字
     */
    private void calWithoutText() {
        mRectF.left = getPaddingLeft() + mCircleOffset;
        mRectF.top = getPaddingTop() + mCircleOffset;
        mRectF.right = getWidth() - getPaddingRight() - mCircleOffset;
        mRectF.bottom = getHeight() - getPaddingBottom() - mCircleOffset;

        //就完啦?
        //你說的對(duì)呀
        //我就確定個(gè)區(qū)域看成,咋滴啦
    }

    /**
     * 精華2
     */
    private void calWithText() {
        mRectF.left = getPaddingLeft() + mCircleOffset;
        mRectF.top = getPaddingTop() + mCircleOffset;
        mRectF.right = getWidth() - getPaddingRight() - mCircleOffset;
        mRectF.bottom = getHeight() - getPaddingBottom() - mCircleOffset;

        if(!TextUtils.isEmpty(mCurrentDrawText)) {
            float text_width = mTextPaint.measureText(mCurrentDrawText);
            mTextRrectF.left = getWidth() / 2.0f - text_width / 2.0f;
            mTextRrectF.top = getHeight() / 2.0f - mTextSize / 2.0f;
            mTextRrectF.right = getWidth() / 2.0f + text_width / 2.0f;
            mTextRrectF.bottom = getHeight() / 2.0f + mTextSize / 2.0f;

            //這里是計(jì)算 文字居中的解決方案 具體請(qǐng)?jiān)L問我搜到的 [這是我找到的](http://blog.csdn.net/hursing/article/details/18703599)
            Paint.FontMetricsInt fontMetrics = mTextPaint.getFontMetricsInt();
            mTextBaseLine = (int) ((mTextRrectF.bottom + mTextRrectF.top - fontMetrics.bottom - fontMetrics.top) / 2);
        } else {
            mIfDrawText = false;
        }

        //這里還是確定個(gè)區(qū)域的問題
        //只不過多了文字的區(qū)域
    }

    /**
     * 這個(gè)套路還是可以再深一點(diǎn)
     * 不過我是新司機(jī)
     * 不會(huì)換檔
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measure(widthMeasureSpec, true), measure(heightMeasureSpec, false));
    }

    /**
     * 測(cè)量 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);
        int padding = isWidth ? getPaddingLeft() + getPaddingRight() : getPaddingTop() + getPaddingBottom();
        if (mode == MeasureSpec.EXACTLY) {
            result = size;
        } else {
            result = isWidth ? getSuggestedMinimumWidth() : getSuggestedMinimumHeight();
            result += padding;
            if (mode == MeasureSpec.AT_MOST) {
                if (isWidth) {
                    result = Math.max(result, size);
                } else {
                    result = Math.min(result, size);
                }
            }
        }
        return result;
    }


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

    public float sp2px(float sp) {
        final float scale = getResources().getDisplayMetrics().scaledDensity;
        return sp * scale;
    }

    private void setProgressTextVisibility(MySecondProgressTextVisibility visibility) {
        mIfDrawText = visibility == MySecondProgressTextVisibility.Visible;
    }

    public void setProgress(float heavy, float moderate, float light) {
        this.mCurrentProgress = heavy + moderate + light;
        this.mCurHeavy = heavy;
        this.mCurModerate = moderate;
        this.mCurLight = light;
        invalidate();
    }

    /**
     * 加個(gè)動(dòng)畫
     * 就會(huì)變成屌屌的
     * 我知道我為什么選progressbar來做第一個(gè)自定義View了
     * 因?yàn)?     * 其他的我也不會(huì)啊
     * @param heavy
     * @param moderate
     * @param light
     */
    public void animProgress(float heavy, float moderate, float light) {
        this.mCurrentProgress = heavy + moderate + light;

        ValueAnimator heavy_animator = ValueAnimator.ofFloat(0, heavy);
        heavy_animator.setInterpolator(new LinearInterpolator());
        heavy_animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mCurHeavy = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });

        ValueAnimator moderate_animator = ValueAnimator.ofFloat(0, moderate);
        moderate_animator.setInterpolator(new LinearInterpolator());
        moderate_animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mCurModerate = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });


        ValueAnimator light_animator = ValueAnimator.ofFloat(0, light);
        light_animator.setInterpolator(new LinearInterpolator());
        light_animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mCurLight = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });

        AnimatorSet animSet = new AnimatorSet();
        animSet.setDuration(1000);
        animSet.playTogether(light_animator, moderate_animator, heavy_animator);
        animSet.start();
    }

    public void setProgressText(String text) {
        this.mCurrentDrawText = text;
        invalidate();
    }
}

第二個(gè)也寫完了君编。
這個(gè)我沒有抄別人的啊。
我抄的是第一個(gè)自定義View 的川慌。
敲完了吃嘿。

感謝
@Alex_Cin
@coco貓
提醒加圖。
已發(fā)布到 JIMBRAY

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末梦重,一起剝皮案震驚了整個(gè)濱河市兑燥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌琴拧,老刑警劉巖降瞳,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蚓胸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)扔枫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門短荐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來忍宋,“玉大人讶踪,你說我怎么就攤上這事泊交±螅” “怎么了研乒?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵雹熬,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我铅乡,道長(zhǎng)阵幸,這世上最難降的妖魔是什么挚赊? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任荠割,我火速辦了婚禮涨共,結(jié)果婚禮上举反,老公的妹妹穿的比我還像新娘扒吁。我一直安慰自己雕崩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著饶火,像睡著了一般肤寝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上缘揪,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天蹈垢,我揣著相機(jī)與錄音袖裕,去河邊找鬼陆赋。 笑死,一個(gè)胖子當(dāng)著我的面吹牛赖临,可吹牛的內(nèi)容都是我干的兢榨。 我是一名探鬼主播顺饮,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼吟逝!你這毒婦竟也來了块攒?” 一聲冷哼從身側(cè)響起佃乘,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤庞呕,失蹤者是張志新(化名)和其女友劉穎程帕,沒想到半個(gè)月后骆捧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年括饶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了图焰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片技羔。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡藤滥,死狀恐怖拙绊,靈堂內(nèi)的尸體忽然破棺而出泳秀,到底是詐尸還是另有隱情嗜傅,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布违寞,位于F島的核電站坞靶,受9級(jí)特大地震影響彰阴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜尿这,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一射众、第九天 我趴在偏房一處隱蔽的房頂上張望叨橱。 院中可真熱鬧,春花似錦愉舔、人聲如沸伙菜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽馏鹤。三九已至踊淳,卻和暖如春迂尝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背垄开。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工榜田, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锻梳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓辩块,卻偏偏與公主長(zhǎng)得像废亭,于是被迫代替她去往敵國(guó)和親豆村。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容