前言
在Android應(yīng)用的開發(fā)里面靴患,UI是非常重要的一部分。一般情況下豁状,我們使用SDK自帶的控件捉偏,加上一些開源庫,已經(jīng)可以實(shí)現(xiàn)大部分的UI效果了泻红。但是要實(shí)現(xiàn)一些自定義效果得UI夭禽,往往需要通過自定義View來實(shí)現(xiàn)。掌握或是精通自定義View谊路,無疑是加分技能讹躯。
繪制
- 方式:重寫繪制方法(最常用的方法:onDraw(Canvas canvas))
繪制:Android里的繪制是在每個View的繪制方法里發(fā)生的,View的繪制方法里寫了什么代碼缠劝,它就會繪制成什么內(nèi)容潮梯。而自定義View就是通過重寫繪制方法,去繪制成想要實(shí)現(xiàn)的效果惨恭。
public class TextView extends View{
...
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
...//TextView的繪制代碼
}
...
}
public class ImageView extends View{
...
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
...//ImageView 的繪制代碼
}
...
}
public class MyView extends View{
...
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
...//MyView 的繪制代碼
}
...
}
onDraw()這個繪制方法秉馏,它負(fù)責(zé)的是View的主體的繪制。例如TextView的文字脱羡、ImageView的圖像萝究,都是在onDraw()里繪制的免都。具體執(zhí)行繪制操作的是onDraw()方法里的Canvas參數(shù)。
- 繪制關(guān)鍵:Canvas帆竹,Canvas是一個繪制工具绕娘,它唯一的功能就是繪制
- Canvas的繪制類方法:drawXX()
- Canvas的輔助類方法:范圍裁切(clipXXX())和幾何變換(Matrix)
- 使用不同的繪制方法來控制遮蓋關(guān)系
測量、布局
布局過程的自定義
- 方式:重寫布局過程的相關(guān)方法
- 測量過程:onMeasure()
- 布局過程:onLayout()
- 場景:
1馆揉、重寫onMeasure()來修改已有的View的尺寸
方式:
1)业舍、重寫 onMeasure() 方法,并在里面調(diào)用 super.onMeasure() 升酣,觸發(fā)原有的自我測量;
2)态罪、在 super.onMeasure() 的下面用getMeasuredWidth()和getMeasuredHeight()來獲取到之前的測量結(jié)果噩茄,并使用自己的算法,根據(jù)測量結(jié)果計算出新的結(jié)果复颈;
3)绩聘、調(diào)用setMeasuredDimension()來保存新的結(jié)果。
public class SquareTextView extends TextView {
...省略部分代碼
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//先執(zhí)行原測量算法
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//獲取原先的測量結(jié)果
int measureWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
//利用原先的測量結(jié)果計算出新尺寸
if (measureWidth>measuredHeight){
measureWidth = measuredHeight;
}else {
measuredHeight = measureWidth;
}
//保存計算后的結(jié)果
setMeasuredDimension(measureWidth,measuredHeight);
}
}
2耗啦、重寫onMeasure()來全新計算自定義View的尺寸
方式:
1)凿菩、重新onMeasure() ,并計算出View的尺寸帜讲;
UNSPECIFIED :不限制
AT_MOST :限制上限
EXACTLY :限制固定值
2)衅谷、使用 resolveSize() 來讓子 View 的計算結(jié)果符合父View的限制
3、重寫onMeasure()和onLayout()來全新計算自定義ViewGroup的內(nèi)部布局
方式:
1)似将、重寫 onMeasure() 來計算內(nèi)部布局
調(diào)用每個子 View 的 measure() 來計算子 View 的尺寸获黔;
計算子 View 的位置并保存子 View 的位置和尺寸;
計算自己的尺寸并用 setMeasuredDimension() 保存在验;
2)玷氏、重寫 onLayout() 來擺放子View
在 onLayout() 里調(diào)用每個子 View 的 layout() ,讓它們保存自己的位置和尺 寸腋舌。
觸摸
- 重寫onTouchEvent() 盏触,在里面寫上你的觸摸反饋算法,并返回 true(關(guān)鍵是
ACTION_DOWN 事件時返回 true )块饺。 - 如果是會發(fā)生觸摸沖突的 ViewGroup 赞辩,還需要重寫onInterceptTouchEvent() ,在事件流開始時返回 false 刨沦,并在確認(rèn)接管事件流時返回一次true诗宣,以實(shí)現(xiàn)對事件的攔截。
- 當(dāng)子 View 臨時需要組織父 View 攔截事件流時想诅,可以調(diào)用父View的requestDisallowInterceptTouchEvent() 召庞,通知父View在當(dāng)前事件流中不 再嘗試通過 onInterceptTouchEvent() 來攔截岛心。
總結(jié)
對View得實(shí)現(xiàn)原理有一個清晰得認(rèn)識,在工作中篮灼,若是遇到相關(guān)bug忘古,或需要實(shí)現(xiàn)自定義View,也知道從何下手诅诱。