Android---初探自定義View(三)

初探自定義View(一)初探自定義View(二)里面,我們都是針對(duì)系統(tǒng)現(xiàn)有的組件進(jìn)行設(shè)計(jì)和修改,那萬一碰到需要自己根據(jù)要求來設(shè)計(jì)一個(gè)全新的View,這就是今天要探討的主要內(nèi)容---自繪控件。


自定義View的三個(gè)過程分別是onMeasure()、onLayout()和onDraw(),在今天這個(gè)DEMO里因?yàn)樯婕暗綄⒆远xView和系統(tǒng)控件的組合使用,所以必須重寫onMeasure()方法來確保自定義View的width和height能夠根據(jù)我們的設(shè)定呈現(xiàn)出來(具體原因和方法參見初探自定義View(一)的相關(guān)內(nèi)容),否則無論設(shè)定width和height為wrap_content或確切值自定義View都會(huì)滿屏,系統(tǒng)控件就無法顯示出來(真啰嗦)。

下面正式進(jìn)入正題,巧婦難為無米之炊,自定義View的第一步往往都是把畫筆顏料準(zhǔn)備好。

1.初始化

    public void init(){
        mCirclePaint=new Paint();
        mCirclePaint.setColor(Color.RED);
        mCirclePaint.setStyle(Paint.Style.FILL);
        mArcPaint=new Paint();
        mArcPaint.setColor(Color.BLACK);
        mArcPaint.setStyle(Paint.Style.STROKE);
        mArcPaint.setStrokeWidth(100);
        mTextPaint=new Paint();
        mTextPaint.setColor(Color.BLUE);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setTextSize(50);
        mTextPaint.setTextAlign(Paint.Align.CENTER);
        mShowSize=mTextPaint.getTextSize();
        Log.d("dd","size is"+mShowSize);
    }
    @Override
    protected void onSizeChanged(int w,int h,int oldW,int oldH){
        super.onSizeChanged(w,h,oldW,oldH);
        length = w;
        x = length/2;
        r = (float) (length*0.5/2);
    }

我們把這個(gè)View分成了三個(gè)部分---圓、弧線和文本,所以這邊初始化了三種畫筆,mShowSize是為之后給文本定位做準(zhǔn)備,x和r分別是圓的圓心坐標(biāo)和半徑,這樣圓就確定了。

2.開始繪制

    public void onDraw(Canvas canvas){
        super.onDraw(canvas);
        rectF=new RectF((float)(length*0.1),
                (float)(length*0.1),
                (float)(length*0.9),
                (float)(length*0.9));
        canvas.drawCircle(x,x,r,mCirclePaint);
        canvas.drawArc(rectF,0,mSweepValue,false,mArcPaint);//若為true則為扇形
        /*canvas.drawText(mShowText,0,mShowText.length(),x,x+(mShowSize/4),mTextPaint);*///
        /*canvas.drawText(mShowText,0,mShowText.length(),x-(width/2),x+(mShowSize/4),mTextPaint);*/
        //0是index
        canvas.drawText(mShowText,0,mShowText.length(),x,x+(mShowSize/4),mTextPaint);
    }

確定了圓心坐標(biāo)和半徑就能畫圓了,而確定了圓弧的外接矩陣的坐標(biāo)就能確定圓弧的位置,具體掃過的角度可通過參數(shù)來設(shè)定,這兩個(gè)用法都比較容易理解。canvas.drawText()是玄機(jī)就多了,系統(tǒng)默認(rèn)繪制文本的x坐標(biāo)是從文本的左下角開始的,這里由于之前我們把文本的重心設(shè)定在的中點(diǎn)mTextPaint.setTextAlign(Paint.Align.CENTER);,如果把文本看成是一條線段的話,那么x就是指線段重點(diǎn)的坐標(biāo),而y坐標(biāo)是文本bottom的位置,如下示意圖:

小時(shí)候被英語支配的恐懼
這樣View的主體就算完成了。

3.上強(qiáng)度

由于這個(gè)DEMO經(jīng)常被用于顯示一個(gè)百分比的比例,所以這里就加一個(gè)動(dòng)態(tài)地改變這個(gè)比例和UI的功能,先上布局文件:

    <com.example.view.PPT
        android:id="@+id/circle"
        android:layout_width="400dp"
        android:layout_height="400dp" />
    <EditText
        android:id="@+id/add"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/ok"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="提交"/>

經(jīng)過測(cè)試,把自定義View的寬高設(shè)定為400dp的時(shí)候能夠較好的顯示和系統(tǒng)組件(太大的話會(huì)把系統(tǒng)組件擠出去),簡單地用EditText和編輯比例,Button來向View提交這個(gè)比例并重繪View,說到重繪View,那必然有一個(gè)監(jiān)聽比例參數(shù)變化的方法,話不多說,上代碼:

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                PPT circle=(PPT) findViewById(R.id.circle);
                okc=Integer.parseInt(editText.getText().toString());
                circle.setSweepValue(okc);
            }
        });
    public void setSweepValue(int sweepValue){
        float z= (float)sweepValue;
        Log.d("dd","z="+sweepValue);
        if (z!=0){
            mSweepValue=(float) (360.0*(sweepValue/100.0));
            mShowText=sweepValue+"%";
            Log.d("dd",""+sweepValue);
        }else {
            mSweepValue=90;
            mShowText=25+"%";
        }
        this.invalidate();
    }

點(diǎn)擊提交按鈕之后,會(huì)把比例值okc通過View暴露出來的方法setSweepValue()來傳入這個(gè)值,最后調(diào)用this.invalidate()方法重繪View。

前面提到的重寫onMeasure():

@Override
    protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec){
        setMeasuredDimension(
                measureWidth(widthMeasureSpec),
                measureHeight(heightMeasureSpec)
        );
    }

    private int measureWidth(int measureSpec){
        int result=0;
        int Mode= View.MeasureSpec.getMode(measureSpec);
        int Size= View.MeasureSpec.getSize(measureSpec);   //自己考慮后的尺寸,若是wrap_content 那就是全屏
        //Size=1080  是像素

        if (Mode== View.MeasureSpec.EXACTLY){
            result=Size;
        }else {
            result=200;
            if (Mode== View.MeasureSpec.AT_MOST){
                result=Math.min(result,Size);

            }
        }
        Log.d("tag","widthsize is " + result);
        return result;
    }
    private int measureHeight(int measureSpec){
        int result=0;
        int Mode= View.MeasureSpec.getMode(measureSpec);
        int Size= View.MeasureSpec.getSize(measureSpec);


        if (Mode== View.MeasureSpec.EXACTLY){
            result=Size;
            Log.d("tag","size is " + result);
        }else {
            result=200;
            if (Mode== View.MeasureSpec.AT_MOST){
                result=Math.min(result,Size);

            }
        }
        /*Log.d("tag","heightsize is " + result);*/
        return result;
    }

具體原理這里就不多bb了,詳情見初探自定義View(一)。
最后上一下效果圖:

效果圖

溜了溜了,吃波牛蛙美滋滋

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容