【Android 開發(fā)】自定義View(中)——基本圖像繪制

內(nèi)容簡概

一、畫線、圓、扇形
二、扇形動(dòng)畫

具體內(nèi)容

一、畫線、圓、扇形、圓弧

(一)創(chuàng)建一個(gè)類(繼承View)用于測試

在這個(gè)類中,我們放置線、圓、扇形、圓弧。

public class TestView extends View {
    // 實(shí)現(xiàn)View的兩個(gè)方法
    public TestView(Context context) {
        super(context);
    }

    public TestView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    
    @Override
    protected void onDraw(Canvas canvas) {
        // 畫線
        // 1. 準(zhǔn)備畫筆 抗鋸齒
        Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setTextSize(70);
        mPaint.setColor(Color.BLACK); // 設(shè)置畫筆顏色
        mPaint.setStrokeWidth(20); // 設(shè)置畫筆粗細(xì)

        // 2.在畫布上畫線
        canvas.drawLine(50,50,300,400,mPaint);
        // x,y為開頭文字左下角左標(biāo)
        canvas.drawText("↑",200,600,mPaint);
        canvas.drawText("drawLine",50,700,mPaint);

        //3.畫圓
        // 這里的top是圓心坐標(biāo),
        canvas.drawArc(600,50,1000,450,0,300,true,mPaint);
        canvas.drawText("↑",770,600,mPaint);
        canvas.drawText("drawArc",650,700,mPaint);

        // useCenter = false
        canvas.drawArc(50,800,450,1200,0,300,false,mPaint);
        canvas.drawText("↑",200,1300,mPaint);
        canvas.drawText("drawArc",50,1400,mPaint);
        canvas.drawText("useCenter=false",50,1500,mPaint);
        // 畫圓的另一種方法
        canvas.drawCircle(800,1000,200,mPaint);
        canvas.drawText("↑",770,1300,mPaint);
        canvas.drawText("drawCircle",650,1400,mPaint);
    }
}

這里的圓是實(shí)心的,如果想要畫空心的圓或者圓弧怎么辦呢?只要多加一句mPaint.setStyle(Paint.Style.STROKE);就可以了,系統(tǒng)默認(rèn)的style為FILL(實(shí)心)。

(二) xml(使用RelativeLayout)
<com.example.test.TestView
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
(三)運(yùn)行結(jié)果圖

左邊為實(shí)心,右邊為空心??招木褪敲枥L外輪廓。(請(qǐng)忽略空心的丑陋文字)。

二、扇形動(dòng)畫

扇形動(dòng)畫是扇形的半徑不變,轉(zhuǎn)的角度在變。下面我用兩個(gè)類分別實(shí)現(xiàn)兩種動(dòng)畫,一種是點(diǎn)擊展開的扇形,一種是自動(dòng)展開的扇形。前者可以用onTouchEvent方法實(shí)現(xiàn),后者可以用Timer(定時(shí)器)或?qū)傩詣?dòng)畫實(shí)現(xiàn)。

(一)點(diǎn)擊展開的扇形

規(guī)定扇形完全展開后就固定為圓形,不再變化。

public class FanAnimation extends View {
    int angle; //每次增長之后的值
    int speed = 20; //增長速度

    public FanAnimation(Context context) {
        super(context);
    }

    public FanAnimation(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        drawFanChart(canvas,Color.BLACK, (float) (angle/360.0),"點(diǎn)擊展開的扇形");
    }

    // onDraw方法不能滿足需求,所以自己寫一個(gè)方法
    private void drawFanChart(Canvas canvas,int color,float rate,String text){
        //畫筆
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setTextSize(70);
        paint.setColor(color);

        //畫扇形
        int endAngle = (int) (360*rate);// 新繪制的扇形endAngle都在增大
        canvas.drawArc(50,100,450,500, 0,endAngle, true,paint);
        canvas.drawText(text,550,300,paint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN){
            // 點(diǎn)擊屏幕 畫一點(diǎn) 這里的angle就是上面的rate
            angle += speed;
            // 控制最大值
            if (angle>360){
                angle = 360;
            }
            // 刷新
            invalidate();
        }
        return true;
    }
}
(二)自動(dòng)展開的扇形——Timer
public class AutoFanAnimation extends View {
    int angle; //每次增長之后的值
    int speed = 5; //增長速度
    public AutoFanAnimation(Context context) {
        super(context);
    }

    public AutoFanAnimation(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 創(chuàng)建定時(shí)器 每個(gè)0.5s 畫一次
        final Timer t = new Timer();
        t.schedule(new TimerTask() {
            @Override
            public void run() {
                angle += speed;
                if (angle > 360){
                    angle = 0; // 重新開始
//                    t.cancel();// 關(guān)閉定時(shí)器
                }
                invalidate(); // 通知系統(tǒng)調(diào)用ondraw
                postInvalidate(); // 子進(jìn)程里面
            }
        },0,100);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        drawFanChart(canvas, Color.BLACK, (float) (angle/360.0),"自動(dòng)展開的扇形");
    }

    // onDraw方法不能滿足需求,所以自己寫一個(gè)方法
    private void drawFanChart(Canvas canvas,int color,float rate,String text){
        //畫筆
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setTextSize(70);
        paint.setColor(color);

        //畫扇形
        int endAngle = (int) (360*rate);
        canvas.drawArc(50,0,450,400, 0,endAngle, true,paint);
        canvas.drawText(text,550,300,paint);
    }
}
(三)自動(dòng)展開的扇形——valueAnimator屬性動(dòng)畫

和自動(dòng)展開的扇形唯一不同的就是onSizeChanged。

public class ValueAnimator extends View {
    int angle; //每次增長之后的值
    int speed = 20; //增長速度
    public ValueAnimator(Context context) {
        super(context);
    }

    public ValueAnimator(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 創(chuàng)建ValueAnimator對(duì)象 設(shè)置范圍0-360
        android.animation.ValueAnimator va = android.animation.ValueAnimator.ofInt(0,360);
        va.setDuration(3000); // 動(dòng)畫時(shí)間
        va.setRepeatCount(android.animation.ValueAnimator.INFINITE);
        // 設(shè)置監(jiān)聽器 監(jiān)聽值的變化
        va.addUpdateListener(new android.animation.ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(android.animation.ValueAnimator valueAnimator) {
                // 獲取某一刻的值
                angle = (int) valueAnimator.getAnimatedValue();
                // 刷新
                invalidate();
            }
        });
        // 啟動(dòng)
        va.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        drawFanChart(canvas, Color.BLACK, (float) (angle/360.0),"屬性動(dòng)畫展開的扇形");
    }
    private void drawFanChart(Canvas canvas,int color,float rate,String text){
        //畫筆
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setTextSize(57);
        paint.setColor(color);

        //畫扇形
        int endAngle = (int) (360*rate);// 新繪制的扇形endAngle都在增大
        canvas.drawArc(50,0,450,400, 0,endAngle, true,paint);
        canvas.drawText(text,550,300,paint);
    }
}
(四)xml(使用LinearLayout)
<com.example.test.FanAnimation
        android:id="@+id/click"
        android:layout_width="wrap_content"
        android:layout_height="250dp"/>

    <com.example.test.AutoFanAnimation
        android:layout_width="wrap_content"
        android:layout_height="200dp"/>

    <com.example.test.ValueAnimator
        android:layout_width="wrap_content"
        android:layout_height="220dp"/>

(五)運(yùn)行結(jié)果圖

最后編輯于
?著作權(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)容