11.2 自定義view

1 簡介

當Android系統內置的View無法實現我們的需求,需要針對業務定製我們想要的View。自定義view分爲兩種:自定義view和定義viewgroup。
自定義View需重寫三個函數:onMeasure()、onLayout()、onDraw()。

  • onMeasure
    onMeasure(int widthMeasureSpec, int heightMeasureSpec)是View讓其父節點知道它想要多大的尺寸。方法的參數widthMeasureSpec和heightMeasureSpec代表 測量模式和寬高的大小。它本身是一個32位的數據,前兩位代表模式,後30位代表尺寸大小。如何獲取。參考附件代碼:
   int widthMode = MeasureSpec.getMode(widthMeasureSpec);
   int widthSize = MeasureSpec.getSize(widthMeasureSpec);

onMeasure包含了3種測量模式:UNSPECIFIED,EXACTLY,AT_MOST。
1. EXACTLY:父view已經強制設置了子view的大小,一般是MATCH_PARENT和固定值
2. UNSPECIFIED:父view對子view沒有任何限制,子view可以是任何大小
3. AT_MOST:子view限制在一個最大範圍內,一般是WARP_CONTENT-包裹內容

  • onLayout ()
    onLayout 讓Android知道View在其父控件中的位置,即距父控件四邊的距離left、right、top、bottom。佈局是繪圖的基礎,只有完成了佈局,才能對View進行繪圖。
  • onDraw()
    onDraw()繪圖的前提是已經對View進行了量算和佈局,View通過調用draw()方法進行繪圖,繪圖的目的就是讓View在UI界面上呈現出來。

2 onMeasure

首頁自定義一個viewgroup 一個button

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <com.example.test.SelftLayout

        android:background="@color/colorPrimary"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.example.test.MyButton
            android:id="@+id/result"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="@color/colorAccent"
            android:text="Hello World!"
            />
    </com.example.test.SelftLayout>
</LinearLayout>

案例—通過改變自定義layout的寬高模式,獲取到的數據不同

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);


    final int mode = MeasureSpec.getMode(widthMeasureSpec);
    final int size = MeasureSpec.getSize(widthMeasureSpec);


    switch (mode) {
        case MeasureSpec.AT_MOST:
            Log.d(TAG, "onMeasure: AT_MOST=" );
            break;
        case MeasureSpec.EXACTLY:
            Log.d(TAG, "onMeasure: EXACTLY=" );
            break;
        case MeasureSpec.UNSPECIFIED:
            Log.d(TAG, "onMeasure: UNSPECIFIED=" );
            break;
    }
    int width = SystemUtil.dp2px(getContext(),200);


    setMeasuredDimension(width,width);
    Log.d(TAG, "onMeasure: AT_MOST=" +size+"---width="+getWidth()+"---height="+getHeight());
}

3.onLayout

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    super.onLayout(changed, l, t, r, b);

    final int childCount = getChildCount();
    
    int left = 0,top = 0,right = 0,bottom = 0;

    for (int x=0;x<childCount;x++){

        final View childAt = getChildAt(x);

        final int measuredWidth = childAt.getMeasuredWidth();
        final int measuredHeight = childAt.getMeasuredHeight();

        left = (getWidth()-measuredWidth)/2;
        top = (getHeight()-measuredHeight)/2;
        right = getWidth()-left;
        bottom = top+measuredHeight;
 
        Log.d(TAG, "onLayout: "+left+"--"+top+"--");
        childAt.layout(left,top,right,bottom);
    }
 
}

4 onDraw

繪製的意思,繪製的內容,形狀。

4.1 Canvas 畫布

Canvas我們可以稱之爲畫布,能夠在上面繪製各種東西,是安卓平臺2D圖形繪製的基礎,非常強大。

4.2 常用api

操作類型 相關API 備註
繪製顏色 drawColor, drawRGB, drawARGB 使用單一顏色填充整個畫布
繪製基本形狀 drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc 依次爲 點、線、矩形、圓角矩形、橢圓、圓、圓弧
繪製圖片 drawBitmap, drawPicture 繪製位圖和圖片
繪製文本 drawText, drawPosText, drawTextOnPath 依次爲 繪製文字、繪製文字時指定每個文字位置、根據路徑繪製文字
繪製路徑 drawPath 繪製路徑,繪製貝塞爾曲線時也需要用到該函數
頂點操作 drawVertices, drawBitmapMesh 通過對頂點操作可以使圖像形變,drawVertices直接對畫布作用、 drawBitmapMesh只對繪製的Bitmap作用
畫布剪裁 clipPath, clipRect 設置畫布的顯示區域
畫布快照 save, restore, saveLayerXxx, restoreToCount, getSaveCount 依次爲 保存當前狀態、 回滾到上一次保存的狀態、 保存圖層狀態、 回滾到指定狀態、 獲取保存次數
畫布變換 translate, scale, rotate, skew 依次爲 位移、縮放、 旋轉、錯切
Matrix(矩陣) getMatrix, setMatrix, concat 實際上畫布的位移,縮放等操作的都是圖像矩陣Matrix, 只不過Matrix比較難以理解和使用,故封裝了一些常用的方法。

4.3 使用

4.3.1 繪製點

	@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
 	     //創建畫筆
        paint = new Paint();
        // 畫筆爲填充模式
        paint.setStyle(Paint.Style.FILL);
        //畫筆顏色
        paint.setColor(Color.RED);
        // 畫筆寬度
        paint.setStrokeWidth(11f);

		canvas.drawPoint(300,300, paint);

4.3.2 繪製線

	@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
 	     //創建畫筆
 	     
        paint = new Paint();
        // 畫筆爲填充模式  STROKE //描邊   FILL //填充   FILL_AND_STROKE //描邊加填充
        paint.setStyle(Paint.Style.FILL);
        //畫筆顏色
        paint.setColor(Color.RED);
        // 畫筆寬度
        paint.setStrokeWidth(11f);

	  canvas.drawLine(300,300,500,600,paint);

4.3.3 繪製矩形

確定一個矩形最少需要四個數據,就是對角線的兩個點的座標值,這裏一般採用左上角和右下角的兩個點的座標。

// 第一種
canvas.drawRect(100,100,800,400,mPaint);

// 第二種
Rect rect = new Rect(100,100,800,400);
canvas.drawRect(rect,mPaint);

// 第三種
RectF rectF = new RectF(100,100,800,400);
canvas.drawRect(rectF,mPaint);

4.3.4 繪製圓

canvas.drawCircle(500,500,400,mPaint); // 繪製一個圓心座標在(500,500),半徑爲400 的圓。

4.3.5 繪製圓角矩形

// 第一種
RectF rectF = new RectF(100,100,800,400);
canvas.drawRoundRect(rectF,30,30,mPaint);

// 第二種
canvas.drawRoundRect(100,100,800,400,30,30,mPaint);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章