android自定義控件

  • 1、座標系

  • 屏幕默認座標系示例View座標系get雨getRaw區別
  • 分類和流程

  • 自定義View繪製流程函數調用鏈

幾個重要的函數

1.構造函數css

構造函數是View的入口,能夠用於初始化一些的內容,和獲取自定義屬性java

View的構造函數有四種重載分別以下:android

public void SloopView(Context context) {} public void SloopView(Context context, AttributeSet attrs) {} public void SloopView(Context context, AttributeSet attrs, int defStyleAttr) {} public void SloopView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {} 

有三個參數的構造函數中第三個參數是默認的Style,這裏的默認的Style是指它在當前Application或Activity所用的Theme中的默認Style,且只有在明確調用的時候纔會生效,以系統中的ImageButton爲例說明:canvas

public ImageButton(Context context, AttributeSet attrs) { //調用了三個參數的構造函數,明確指定第三個參數 this(context, attrs, com.android.internal.R.attr.imageButtonStyle); } public ImageButton(Context context, AttributeSet attrs, int defStyleAttr) { //此處調了四個參數的構造函數,無視便可 this(context, attrs, defStyleAttr, 0); }

排除了兩個以後,只剩下一個參數和兩個參數的構造函數,他們的詳情以下:ide

//通常在直接New一個View的時候調用。 public void SloopView(Context context) {} //通常在layout文件中使用的時候會調用,關於它的全部屬性(包括自定義屬性)都會包含在attrs中傳遞進來。 public void SloopView(Context context, AttributeSet attrs) {} 

如下方法調用的是一個參數的構造函數:函數

//在Avtivity中 SloopView view new SloopView(this); 

如下方法調用的是兩個參數的構造函數:oop

//在layout文件中 - 格式爲: 包名.View名 <com.sloop.study.SloopView android:layout_width"wrap_content" android:layout_height"wrap_content"/> 

2.測量View大小(onMeasure)佈局

View的大小不只由自身所決定,同時也會受到父控件的影響,爲了咱們的控件能更好的適應各類狀況,通常會本身進行測量。this

測量View大小使用的是onMeasure函數,咱們能夠從onMeasure的兩個參數中取出寬高的相關數據:spa

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthsize = MeasureSpec.getSize(widthMeasureSpec); //取出寬度的確切數值 int widthmode = MeasureSpec.getMode(widthMeasureSpec); //取出寬度的測量模式 int heightsize = MeasureSpec.getSize(heightMeasureSpec); //取出高度的確切數值 int heightmode = MeasureSpec.getMode(heightMeasureSpec); //取出高度的測量模式 } 

從上面能夠看出 onMeasure 函數中有 widthMeasureSpec 和 heightMeasureSpec 這兩個 int 類型的參數, 毫無疑問他們是和寬高相關的, 但它們其實不是寬和高, 而是由寬、高和各自方向上對應的測量模式來合成的一個值:

測量模式一共有三種, 被定義在 Android 中的 View 類的一個內部類View.MeasureSpec中:

模式 二進制數值 描述
UNSPECIFIED 00 默認值,父控件沒有給子view任何限制,子View能夠設置爲任意大小。
EXACTLY 01 表示父控件已經確切的指定了子View的大小。
AT_MOST 10 表示子View具體大小沒有尺寸限制,可是存在上限,上限通常爲父View大小。

 

用 MeasureSpec 的 getSize是獲取數值, getMode是獲取模式。

注意:

若是對View的寬高進行修改了,不要調用 super.onMeasure( widthMeasureSpec, heightMeasureSpec); 要調用 setMeasuredDimension( widthsize, heightsize)這個函數。

3.肯定View大小(onSizeChanged)

這個函數在視圖大小發生改變時調用。

由於View的大小不只由View自己控制,並且受父控件的影響,因此咱們在肯定View大小的時候最好使用系統提供的onSizeChanged回調函數。

onSizeChanged以下:

@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); } 

四個參數,分別爲 寬度,高度,上一次寬度,上一次高度。

只需關注 寬度(w), 高度(h) 便可,這兩個參數就是View最終的大小。

4.肯定子View佈局位置(onLayout)

肯定佈局的函數是onLayout,它用於肯定子View的位置,在自定義ViewGroup中會用到,他調用的是子View的layout函數。

在自定義ViewGroup中,onLayout通常是循環取出子View,而後通過計算得出各個子View位置的座標值,而後用如下函數設置子View位置。

child.layout(l, t, r, b); 

5.繪製內容(onDraw)

onDraw是實際繪製的部分,也就是咱們真正關心的部分,使用的是Canvas繪圖。

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

6.對外提供操做方法和監聽回調

自定義完View以後,通常會對外暴露一些接口,用於控制View的狀態等,或者監聽View的變化.

  • 3、Canvas

操做類型

相關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比較難以理解和使用,故封裝了一些經常使用的方法。

    private Paint mPaint = new Paint();初始化畫筆

    private void initPaint() {

      mPaint.setColor(Color.BLACK);//設置畫筆顏色

      mPaint.setStyle(Paint.Style.FILL);//設置畫筆模式爲填充

      mPaint.setStrokeWidth(10f); //設置畫筆寬度爲10px

    }

    public SloopView(Context context, AttributeSet attrs) {

      super(context, attrs); initPaint();

    }

繪製點:       canvas.drawPoint(200, 200, mPaint);

繪製線:       canvas.drawLine(300,300,500,600,mPaint);

繪製矩形:  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);

繪製圓:       canvas.drawCircle(500,500,400,mPaint);

繪製圓弧:  public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint){}

4、注意事項:

一、在 xml中建立了一個view時,全部在xml中聲明的屬性都會被傳入到view的構造方法中的AttributeSet類型的參數當中。 經過調用Context的obtainStyledAttributes()方法返回一個TypedArray對象。而後直接用TypedArray對象獲取自定義屬性的值。TypedArray對象是共享的資源,因此在獲取完值以後必需要調用recycle()方法來回收

二、自定義控件的屬性發生改變以後,控件的樣子也可能發生改變,在這種狀況下就須要調用invalidate()方法讓系統去調用view的onDraw()從新繪製

三、在onDraw方法中開始繪製以前,應該讓畫筆Paint對象的信息初始化完畢。這是由於View的從新繪製是比較頻繁的,這就可能屢次調用onDraw,因此初始化的代碼不該該放在onDraw方法裏


 參考:http://www.gcssloop.com/customview/CustomViewIndex
相關文章
相關標籤/搜索