Android之自定義View以及畫一個時鐘

概述:

當Android自帶的View滿足不了開發者時,自定義View就發揮了很好的作用。
建立一個自定義View,需要繼承於View類,並且實現其中的至少一個構造函數和兩個方法:onMeasure()和onDraw();
onMeasure()用於設置自定義View的尺寸,onDraw()用於繪製View中的內容。

在onDraw()方法中,需要調用畫筆繪製圖形或文本,繪製的模板時Canvas對象, Canvas類中用來繪製圖形文本的方法有:

  • drawRect(RectF rect, Paint paint) //繪製區域,參數一爲RectF一個區域

  • drawPath(Path path, Paint paint) //繪製一個路徑,參數一爲Path路徑對象

  • drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) //貼圖,參數一就是我們常規的Bitmap對象,參數二是源區域(這裏是bitmap),參數三是目標區域(應該在canvas的位置和大小),參數四是Paint畫刷對象,因爲用到了縮放和拉伸的可能,當原始Rect不等於目標Rect時性能將會有大幅損失。

  • drawLine(float startX, float startY, float stopX, float stopY, Paintpaint) //畫線,參數一起始點的x軸位置,參數二起始點的y軸位置,參數三終點的x軸水平位置,參數四y軸垂直位置,最後一個參數爲Paint 畫刷對象。

  • drawPoint(float x, float y, Paint paint) //畫點,參數一水平x軸,參數二垂直y軸,第三個參數爲Paint對象。

  • drawText(String text, float x, floaty, Paint paint) //渲染文本,Canvas類除了上面的還可以描繪文字,參數一是String類型的文本,參數二x軸,參數三y軸,參數四是Paint對象。

  • drawOval(RectF oval, Paint paint)//畫橢圓,參數一是掃描區域,參數二爲paint對象;

  • drawCircle(float cx, float cy, float radius,Paint paint)// 繪製圓,參數一是中心點的x軸,參數二是中心點的y軸,參數三是半徑,參數四是paint對象;

  • drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//畫弧,參數一是RectF對象,一個矩形區域橢圓形的界限用於定義在形狀、大小、電弧,參數二是起始角(度)在電弧的開始,參數三掃描角(度)開始順時針測量的,參數四是如果這是真的話,包括橢圓中心的電弧,並關閉它,如果它是假這將是一個弧線,參數五是Paint對象。

    繪製圖形需要畫筆Paint對象,Paint類中的方法有:

  • setARGB(int a, int r, int g, int b) // 設置 Paint對象顏色,參數一爲alpha透明值

  • setAlpha(int a) // 設置alpha不透明度,範圍爲0~255

  • setAntiAlias(boolean aa) // 是否抗鋸齒

  • setColor(int color) // 設置顏色,這裏Android內部定義的有Color類包含了一些常見顏色定義

  • setTextScaleX(float scaleX) // 設置文本縮放倍數,1.0f爲原始

  • setTextSize(float textSize) // 設置字體大小

  • setUnderlineText(booleanunderlineText) // 設置下劃線

Demo

一個自定義時鐘視圖的寫法:

public class MyView extends View {

    private int width;
    private int height;
    private Paint mPaintLine;
    private Paint mPaintCircle;
    private Paint mPaintHour;
    private Paint mPaintMinute;
    private Paint mPaintSec;
    private Paint mPaintText;
    private Calendar mCalendar;
    public static final int NEED_INVALIDATE = 0X23;

    //每隔一秒,在handler中調用一次重新繪製方法
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {

            switch (msg.what){
                case NEED_INVALIDATE:
                    mCalendar = Calendar.getInstance();
                    invalidate();//告訴UI主線程重新繪製
                    handler.sendEmptyMessageDelayed(NEED_INVALIDATE,1000);
                    break;
                default:
                    break;
            }
        }
    };

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

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);

        mCalendar = Calendar.getInstance();

        mPaintLine = new Paint();
        mPaintLine.setColor(Color.BLUE);
        mPaintLine.setStrokeWidth(10);

        mPaintCircle = new Paint();
        mPaintCircle.setColor(Color.GREEN);//設置顏色
        mPaintCircle.setStrokeWidth(10);//設置線寬
        mPaintCircle.setAntiAlias(true);//設置是否抗鋸齒
        mPaintCircle.setStyle(Paint.Style.STROKE);//設置繪製風格

        mPaintText = new Paint();
        mPaintText.setColor(Color.BLUE);
        mPaintText.setStrokeWidth(10);
        mPaintText.setTextAlign(Paint.Align.CENTER);
        mPaintText.setTextSize(40);

        mPaintHour = new Paint();
        mPaintHour.setStrokeWidth(20);
        mPaintHour.setColor(Color.BLUE);

        mPaintMinute = new Paint();
        mPaintMinute.setStrokeWidth(15);
        mPaintMinute.setColor(Color.BLUE);

        mPaintSec = new Paint();
        mPaintSec.setStrokeWidth(10);
        mPaintSec.setColor(Color.BLUE);

        handler.sendEmptyMessage(NEED_INVALIDATE);//向handler發送一個消息,讓它開啓重繪
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int circleRadius = 400;
        //畫出大圓
        canvas.drawCircle(width / 2, height / 2, circleRadius, mPaintCircle);
        //畫出圓中心
        canvas.drawCircle(width / 2, height / 2, 20, mPaintCircle);
        //依次旋轉畫布,畫出每個刻度和對應數字
        for (int i = 1; i <= 12; i++) {
            canvas.save();//保存當前畫布
            canvas.rotate(360/12*i,width/2,height/2);
            //左起:起始位置x座標,起始位置y座標,終止位置x座標,終止位置y座標,畫筆(一個Paint對象)
            canvas.drawLine(width / 2, height / 2 - circleRadius, width / 2, height / 2 - circleRadius + 30, mPaintCircle);
            //左起:文本內容,起始位置x座標,起始位置y座標,畫筆
            canvas.drawText(""+i, width / 2, height / 2 - circleRadius + 70, mPaintText);
            canvas.restore();//
        }

        int minute = mCalendar.get(Calendar.MINUTE);//得到當前分鐘數
        int hour = mCalendar.get(Calendar.HOUR);//得到當前小時數
        int sec = mCalendar.get(Calendar.SECOND);//得到當前秒數

        float minuteDegree = minute/60f*360;//得到分針旋轉的角度
        canvas.save();
        canvas.rotate(minuteDegree, width / 2, height / 2);
        canvas.drawLine(width / 2, height / 2 - 250, width / 2, height / 2 + 40, mPaintMinute);
        canvas.restore();

        float hourDegree = (hour*60+minute)/12f/60*360;//得到時鐘旋轉的角度
        canvas.save();
        canvas.rotate(hourDegree, width / 2, height / 2);
        canvas.drawLine(width / 2, height / 2 - 200, width / 2, height / 2 + 30, mPaintHour);
        canvas.restore();

        float secDegree = sec/60f*360;//得到秒針旋轉的角度
        canvas.save();
        canvas.rotate(secDegree,width/2,height/2);
        canvas.drawLine(width/2,height/2-300,width/2,height/2+40,mPaintSec);
        canvas.restore();

    }
}

需要在佈局中加載自定義View,名字必須是全名(包括包名):
activity_timer

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <com.example.administrator.selfdefinedview.widget.MyView
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

主活動setContentView就行了

public class TimerActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_timer);
    }
}

演示結果:
這裏寫圖片描述

我們猿類工作壓力大,很需要有自己的樂趣,於是乎,我開通了音樂人賬號,以後的作品將會上傳到我的音樂人小站上。如果這篇博客幫助到您,希望您能多關注,支持,鼓勵我將創作進行下去,同時也祝你能在工作和生活樂趣兩發麪都能出彩!

網易雲音樂人,直接打開客戶端搜索音樂人 “星河河”

豆瓣音樂人地址:https://site.douban.com/chuxinghe/ 星河河

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章