Android 自定義View
前言
首先我們先了解一下,什么叫view?Android官方文檔對(duì)View的解釋是這樣的:表示用戶(hù)界面組件的基本構(gòu)建塊,視圖占據(jù)屏幕上的矩形區(qū)域,負(fù)責(zé)繪圖和事件處理。以上可以看出view是程序與用戶(hù)之間進(jìn)行交互的橋梁。view的形狀,大小,表現(xiàn)形式多種多樣,所有就會(huì)發(fā)現(xiàn)Android系統(tǒng)能提供給我們的有時(shí)候并不能滿(mǎn)足我們的需求,所以就會(huì)需要程序員去自定義view。
下面我就介紹以下如何自定義view,我將自定義View基礎(chǔ)、自定義View繪制流程、事件分發(fā)機(jī)制這三個(gè)方面來(lái)介紹。
一 自定義View基礎(chǔ)
1.1 坐標(biāo)系
屏幕坐標(biāo)系與數(shù)學(xué)坐標(biāo)系的差異


1.1.1 屏幕坐標(biāo)系

1.1.1 view的坐標(biāo)系
注意:View的坐標(biāo)系都是相對(duì)于父控件而言。

1.2 顏色
三原色



1.3 分類(lèi)
根據(jù)用途來(lái)分,一般將自定義分為兩種:即自定義控件和自定義布局.

1.4 自定義屬性
自定義屬性步驟

二 自定義view繪制流程
2.1 繪制流程

2.2 相關(guān)函數(shù)介紹
2.2.1 構(gòu)造函數(shù)
一個(gè)參的構(gòu)造,一般在java代碼中直接new一個(gè)View時(shí)調(diào)用。

兩個(gè)參的構(gòu)造,一般在Layout文件中使用的時(shí)候調(diào)用,關(guān)于它的所有屬性(包括自定義屬性)都會(huì)通過(guò)attrs傳遞進(jìn)來(lái)。

三個(gè)參數(shù)的構(gòu)造,第三個(gè)參數(shù)是默認(rèn)的Style,這里的默認(rèn)的Style是指它在當(dāng)前Application或Activity所用的Theme中的默認(rèn)Style。

四個(gè)參數(shù)的構(gòu)造,第四個(gè)參數(shù)是指向一個(gè)style的ID,但是是在defStyleAttr為0,或者defStyle不為0,但theme沒(méi)有為defStyleAttr屬性賦值時(shí)起作用。

2.2.2 測(cè)量view的大小函數(shù)-onMeasure()
作用:測(cè)量View的大小,并從widthMeasureSpec 和 heightMeasureSpec中取出寬高的相關(guān)數(shù)據(jù),它們其實(shí)不是寬和高, 而是由寬、高和各自方向上對(duì)應(yīng)的測(cè)量模式來(lái)合成的一個(gè)值。


測(cè)量模式:
三種測(cè)量模式,通過(guò)MeasureSpec.getMode()得到測(cè)量模式, Measure.getSize()得到測(cè)量數(shù)值。

2.2.3 確定view的大小函數(shù)-onSizeChanged()
作用:確定View大小,在視圖大小發(fā)生改變時(shí)調(diào)用,它有四個(gè)參數(shù),分別為寬度,高度,上一次寬度,上一次高度。

2.2.4 確定子view的布局-onLayout()
作用:它用于確定子View的位置,在自定義ViewGroup中會(huì)用到,他調(diào)用的是子View的layout函數(shù)。它有四個(gè)參數(shù)如下:

2.2.5 繪制view的函數(shù)-onDraw()

作用:繪制內(nèi)容,使用canvas進(jìn)行繪圖.

三 事件分發(fā)機(jī)制
為什么要有事件分發(fā)機(jī)制?
有時(shí)候界面上的view并不是很規(guī)則整齊的排列在一起,View之間是有可能重疊在一起的,當(dāng)我們點(diǎn)擊的地方有多個(gè)View響應(yīng)時(shí),這個(gè)點(diǎn)擊事件應(yīng)該分發(fā)給誰(shuí)?為了解決這一部分就有了事件分發(fā)機(jī)制。
3.1 事件分發(fā)核心函數(shù)

以上三個(gè)方法都有一個(gè)boolean類(lèi)型的返回值,通過(guò)返回true或者false來(lái)控制事件的流程.
3.2 事件分發(fā)流程
責(zé)任鏈模式,即如果自己能處理就攔截下來(lái)自己處理,如果不能處理或者不確定就交給責(zé)任鏈中的下一個(gè)對(duì)象。如下圖:

3.2.1 事件分發(fā)機(jī)制流程詳解
事件傳遞順序:

注意:事件傳遞過(guò)程先執(zhí)行分發(fā),再執(zhí)行攔截,事件傳遞返回 true,表示事件被攔截,交給自己的onTouchEvent處理;false,表示不攔截,向下傳遞。
事件處理順序:

注意:事件的處理都要進(jìn)過(guò)onTouchEvent,事件處理返回true,表示事件自己處理,false,表示向上傳遞。
3.2.2 事件分發(fā)機(jī)制流程概括
(1)事件如果被消費(fèi),就意味著事件傳遞消息被終止。
(2)如果事件一直沒(méi)有被消費(fèi)就會(huì)傳遞給activity,如果activity也不需要就會(huì)被拋棄。
(3)判斷事件是否被消費(fèi)是根據(jù)返回值,并不是根據(jù)你是否使用了該事件。
Android 事件分發(fā),一般可以理解為:
(a)ViewGroup對(duì)點(diǎn)擊事件的分發(fā)機(jī)制。
(b)View對(duì)點(diǎn)擊事件的分發(fā)機(jī)制。
3.3 MotionEvent對(duì)象
根據(jù)面向?qū)ο蟮乃枷?,事件被封裝成MotionEvent對(duì)象。

對(duì)于單指觸控來(lái)說(shuō),一次簡(jiǎn)單的交互流程是:

3.4 ViewGroup的事件分發(fā)
注意:ViewGroup的事件分發(fā)不僅要考慮自身,還要考慮子View.
ViewGroup的分發(fā)流程:

3.4.1 子view存在重合點(diǎn)時(shí)的處理

情況一:
只有View1可以點(diǎn)擊時(shí),該點(diǎn)擊事件分配給View1
情況二:
只有View2可以點(diǎn)擊時(shí),該點(diǎn)擊事件分配給View2
情況三:
View1、View2均可點(diǎn)擊時(shí),該點(diǎn)擊事件分配給View2,如果View2將事件消費(fèi)掉了,則View1將接收不到.
3.4.2 view的可點(diǎn)擊情況分類(lèi):
onClick
onLongClick
onContextClick
android:clickable=“true”
button ,ImageButton,CheckBox默認(rèn)是可點(diǎn)擊的。
3.5 view的事件分發(fā)流程

3.6 總結(jié)

以上只是個(gè)人對(duì)自定義view的理解.有不對(duì)的地方,歡迎指正!