面試自定義控件回答點

相信大家在面試的時候經常會遇到自定義view相關的面試題,下面我給大家說一下回答的思路。
1、首先android的繪製流程,在activity創建的時候,ActivityThread會調用handleResumeActivity,此時DecorView會和ViewRootImpl會相關聯,並把ViewRootImpl設置爲DecorView的父類,View的繪製是從ProformTraverslas開始的。
2、接着就可以分析常見的三個方法 measure layout draw
3、如果有事件相關的要求的重寫onTouchEvent方法 同時可以擴展回答事件攔截。
4、可以着擴展viewDragHalper 和gesturepractice 的區別以及用法
5、可以擴展到android 雙緩存屏幕刷新機制,以及繪製卡頓等問題。
能回答到上面5點基本自定義view算完事。

下面我來一點點的分析
1、ActivityThread會收到內部類IApplicationThread發送的一個創建Activity的消息(AMS是如何給IApplicationThread發消息的這屬於IBinder相關知識了),這個方法名爲handleLancherActivity,在這個方法裏面主要是順序的調用Activity的生命週期了。performLancherActivity(用於activity的創建)、handleResumeActivity(用於繪製相關的是接下來主要分析的方法),performPauseActivityIfNeed(activity不可見時調用)
手撕一下performLancherActivity。如下圖
在這裏插入圖片描述
2、接下來說onmeasure onlayout ondraw
onmeasure主要主要是測量控件的大小,詳細說一下測量模式,在重寫onMesurce的時候主要有兩個參數widthMeasurceSpace 和heightMeasurceSpace,兩個差不多,這裏說一下widthMeasurceSpace。
widthMeasurceSapce 是一個32位的int值,前兩位表示的是寬高的模式,分別有三種exactly(準確的)acmost(至少)和unspecified(未確認的),後面的30位標識具體的期望值。
widthMeasurceSapce 是由父類傳遞過來的,具體計算規則
1、如果父控件值確定寬度,子控件也確定寬度,那麼MeasurceSapce 的mode 是exactly size是子控件的大小。
2、如果父控件確定寬度,子控件是match_parent,那麼
MeasurceSapce的mode 是exactly size是父控件的大小。
3、如果控件確定寬度,子控件是wrap_content,那麼MeasurceSapce的mode 是at_most size小於父控件size。

4、父控件是at_most,子控件確定寬度,那麼measurceSapce的mode 是exactly size是子控件大小。
5、父控件是at_most,子控件爲wrap_content,那麼measurceSpace的mode at_most size是包含自己的內容的size
6、父控件是at_most,子控件是match_parent,mode是at_most size是父控件size。

7、父控件是未指定的,子控件是指定的 mode是exactly size是0.
8、父控件是未指定的,子控件是wrap_content 或是match_parent mode是未指定 size是0。
最後調用setMeasureDimension將測量的數據保存下來。
onlayout 主要是ViewGroup調用了根據自己的規則來放自View的位置。
ondraw ondraw方法裏面會獲取一個canvas,我可以用這個canvas來畫我們想畫的東西,例如矩形 橢圓 弧線 bitmap text等,也可以位畫筆添加顏色風格等。可用通過requestLayout 來重新測量和佈局,invalidate來重新繪製。

下來說一下事件的傳遞機制,在自動控件中也會用到這方面的相關知識,何時讓父view響應事件何時子控件響應事件。
主要注意三個方法 dispathTouchEvent、onInterceptTouchEvent,和onTouchEvent,其中view控件是沒有onInterceptTouchevent方法的。

ViewGroup 的dispathTouchEvent主要分爲三步
1、是否攔截事件。
2、調用dispatchTransformedTouchEvent 遞歸dispathTouchEvent分發事件。
3、根據mFristTouchTarget,重新分發事件。

是否攔截事件 會根據down事件和mFristTouchTarget!= null來判斷是否調用攔截相關的邏輯,所以down事件一定會走onInterceptTouchevent相關方法,或者有子view獲取了Touch事件mFristTouchTarget不爲null也會走相關攔截邏輯。

遍歷ViewGroup中的所有子view,找到觸摸點和view一致的view,調用子View的disPathTouchEvent方法,在這裏面會先判斷TouchListener有沒有消耗事件,如果沒有則會調用onTouchEvent方法返回true,則會將此View賦值給ViewGroup的mFristTouchTarget對象,並記錄事件已經下發。

mFristTouchTarget 對mFristTouchTarget進行判斷,如果爲空則直接調用viewGroup自己的onToucheEvent方法。如果不爲空但是父控件攔截了事件,則會下發cancel事件。(例如ScrollView裏面添加一個子view,當我們觸摸子View的時候事件能夠正常傳遞到子view,但是當滑動的時候會觸發ScrollView控件的攔截事件,scrollview收到事件,上一個子view只能收到一個cancel事件)

mFristTouchTarget 是一個鏈表,每一個手指的down都可以被記錄成一個TouchTarget

requestDisallowInterceptTouchEvent(true) 要求父控件不攔截事件。

viewDragHalper 和gesturepractice 只是對onTouchEvent進行封裝,幫助開發者更快更簡單的處理拖拽事件(ViewDragHalper)和手勢處理事件(gesturepractice)。

屏幕刷新機制可以參考https://juejin.im/post/5d837cd1e51d4561cb5ddf66

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章