在Android中,無論是熟知的布局,還是控件,統統全都繼承自基類View。

自定義View實現有幾種:
- ① 自定義組合控件:多個控件組合成為一個新的控件,方便多處復用
- ② 繼承系統View控件:繼承自TextView等系統控件,在系統控件的基礎功能上進行擴展
- ③ 繼承View:不復用系統控件邏輯,繼承View進行功能定義
- ④ 繼承系統ViewGroup:繼承自LinearLayout等系統控件,在系統控件的基礎功能上進行擴展
- ⑤ 繼承ViewGroup:不復用系統控件邏輯,繼承ViewGroup進行功能定義
一、View的繪製流程
View的繪製基本由measure()、layout()、draw()這個三個函數完成:
- measure:測量View的寬高,主要是View中的:measure(),setMeasuredDimension(),onMeasure()方法。
- layout:計算當前View以及子View的位置,主要是View中的:layout(),onLayout(),setFrame()方法。
- draw:視圖的繪製工作,主要是View中的:draw(),onDraw()方法。
二、Android 屏幕坐標系
在Android坐標系中,以屏幕左上角作為原點,這個原點向右是X軸的正軸,向下是Y軸正軸。

根據以上的坐標,結合View基類的相關API,涉及View的一些坐標方法,比如:
- getTop:View到其父布局頂邊的距離
- getLeft:View到其父布局左邊的距離
- getBottom:View到其父布局頂邊的距離
- getRight:View到其父布局左邊的距離
結合以上的API,可以計算出視圖的寬度和高度,可以使用如下方式計算:
- width = getRight – getLeft;
- height = getBottom – getTop
三、自定義View開發的步驟
這裡我們介紹最複雜的一種,自定義View。
3.1 構造函數
無論是繼承系統View還是直接繼承View,都需要對構造函數進行重寫,構造函數有多個,至少要重寫其中一個才行。
public class CustomView extends View{
/**
* 代碼中New實例化時 調用該方法
*/
public CustomView(Context context){
super(context);
}
/**
* 在xml布局文件中使用時會自動調用該方法
*/
public CustomView(Context context, AttributeSet attrs){
super(context, attrs);
}
...
//更多參數的構造函數
}3.2 自定義屬性
Android系統的控件以android開頭的都是系統自帶的屬性。為了方便配置自定義View的屬性,我們也可以自定義屬性值。Android自定義屬性可分為以下幾步:
- 1、自定義一個View
- 2、編寫values/attrs.xml,在其中編寫styleable和item等標籤元素
- 3、在布局文件中View使用自定義的屬性(注意namespace)
- 4、在View的構造方法中通過TypedArray獲取
attrs.xml文件示例如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="test">
<attr name="text" format="string" />
<attr name="testAttr" format="integer" />
</declare-styleable>
</resources>代碼實現示例如下:
public class MyTextView extends View {
private static final String TAG = MyTextView.class.getSimpleName();
//在View的構造方法中通過TypedArray獲取
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.test);
String text = ta.getString(R.styleable.test_testAttr);
int textAttr = ta.getInteger(R.styleable.test_text, -1);
Log.e(TAG, "text = " + text + " , textAttr = " + textAttr);
ta.recycle();
}
}布局文件使用示例如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res/com.example.test"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.test.MyTextView
android:layout_width="100dp"
android:layout_height="200dp"
app:testAttr="520"
app:text="helloworld" />
</RelativeLayout>四、Measure()
MeasureSpec
MeasureSpec是View的內部類,它封裝了一個View的尺寸,在onMeasure()當中會根據這個MeasureSpec的值來確定View的寬高。MeasureSpec的值保存在一個int值當中。一個int值有32位,前兩位表示模式mode後30位表示大小size。即MeasureSpec = mode + size。
在MeasureSpec當中一共存在三種mode:
- UNSPECIFIED:無限制,View對尺寸沒有任何限制,View設置為多大就應當為多大。
- EXACTLY :精準模式,View需要一個精確值,這個值即為MeasureSpec當中的Size。對應的是match_parent。
- AT_MOST:最大模式,View的尺寸有一個最大值,View不可以超過MeasureSpec當中的Size值。對應的是wrap_content。
常見的使用方式如下:
// 獲取測量模式(Mode)
int specMode = MeasureSpec.getMode(measureSpec)
// 獲取測量大小(Size)
int specSize = MeasureSpec.getSize(measureSpec)
// 通過Mode 和 Size 生成新的SpecMode
int measureSpec=MeasureSpec.makeMeasureSpec(size, mode);onMeasure
整個測量過程的入口位於View的measure方法當中,該方法做了一些參數的初始化之後調用了onMeasure方法,這裡我們主要分析onMeasure。onMeasure源碼如下:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}- setMeasuredDimension(int measuredWidth, int measuredHeight) :該方法用來設置View的寬高,在我們自定義View時也會經常用到。
- getDefaultSize(int size, int measureSpec):該方法用來獲取View默認的寬高。
- getSuggestedMinimumWidth():getHeight和該方法原理是一樣的
五、Layout()
layout()過程,對於View來說用來計算View的位置參數,對於ViewGroup來說,除了要測量自身位置,還需要測量子View的位置。layout()方法是整個Layout()流程的入口,並在layout方法中調用了onLayout方法,主要是進行子View的計算。
六、Draw()
draw流程也就是的View繪製到屏幕上的過程,整個流程的入口在View的draw()方法之中,而源碼注釋也寫的很明白,整個過程可以分為6個步驟:
- 繪製背景
- 有過有必要,保存當前canvas
- 繪製View的內容
- 繪製子View
- 根據需要,繪製邊緣、陰影等效果
- 繪製裝飾,如滾動條等等
七、總結
自定義View在Android的開發中的重要性還是很大的,因為僅僅靠系統提供的控件和組件,無論是美觀度還是使用度,再或者是新特性上,都無法滿足特定的業務場景。因此,常常要用到自定義View,這就要求要在自己的項目自己完成特殊控件的自主開發。自定義控件在開發過程中也屬於重點和難點,應該多花時間進行學習和研究,重點有以下幾個:
- 控件屬性的定義、設置和使用
- 交互處理:事件交互和處理屬於重中之重,常常要和事件分髮結合在一起研究。
- Canvas和Paint:在進行自定義View開發時,往往會通過畫布自己使用畫筆進行繪製,這就要求要對Paint、Path、Canvas要做着重的掌握。
原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/281175.html
微信掃一掃
支付寶掃一掃