2025-07-08

《Android進階之光》學習筆記之View體系與自定義View。對於一個APP來說,與用戶交互、將內容展示給用戶,都是一個個View通過擴展實現的。View是Android所有控件的基類,我們平常所用的TextVew和ImageView都是繼承自View的。

而用的LinearLayout、RelativeLayout和FrameLayout佈局控件繼承自ViewGroup,ViewGroup是View的組合,包含很多View和ViewGroup,而它包含的ViewGroup又可以包含View和ViewGroup,依次類推,形成一個View樹。

而ViewGroup也是繼承自View。

 

public abstract class ViewGroup extends View implements ViewParent,ViewManager{
...
}

 

坐標系

Android系統中有兩種坐標系,分別為Android坐標系View坐標系

Android坐標系

在Android中將屏幕左上角的頂點作為Android坐標系的原點,這個原點向右是X軸正方向,向下是Y軸正方向。在觸控事件中,使用(getRawX(),getRawY())獲得的坐標也是Android坐標系的坐標。

View坐標系

View坐標系

(1)View獲取自身的寬和高

 

width=getRight()-getLeft();
height=getBottom()-getTop();

此外系統給我們提供瞭獲取View寬和高的方法,getHeight()用來獲取View自身的高度,getWidth()用來獲取View自身的寬度。

 

源碼如下:

 

public final int getHeight(){
return mBottom-mTop;
}

public final int getWidth(){
return mRight-mLeft;
}

(2)View自身的坐標

 

通過如下方法可以獲得View到其父控件(ViewGroup)的距離;

getTop():獲取View自身頂邊到其父佈局頂邊的距離。

getLeft():獲取View自身左邊到其父佈局左邊的距離。

getRight():獲取View自身右邊到其父佈局左邊的距離。

getBottom():獲取View自身底邊到其父佈局頂邊的距離。

(3)MotionEvent提供的方法

假設View坐標系示意圖中的圓點是觸摸點,此外View和ViewGroup的點擊事件都由onTouchEvent(MotionEvent event)方法來處理。MotionEvent在用戶交互中作用重大,其內部提供瞭很多事件常量,比如ACTION_DOWN、ACTION_UP和ACTION_MOVE。此外,MotionEvent也提供瞭獲取焦點坐標的各種方法。

getX():獲取點擊事件距離控件左邊的距離,即視圖坐標。

getY():獲取點擊事件距離控件頂邊的距離,即視圖坐標。

getRawX():獲取點擊事件距離整個屏幕左邊的距離,即絕對坐標。

getRawY():獲取點擊事件距離整個屏幕頂邊的距離,即絕對坐標。

View的滑動

基本思想:當點擊事件傳到View時,系統記下觸摸點的坐標,手指移動時系統記下移動後觸摸的坐標並算出偏移量,並通過偏移量來修改View的坐標。

View的6種滑動方式:

layout()
offsetLeftAndRight()與offsetTopAndBottom()
layoutParams
動畫
scrollTo與scrollBy
Scroller

解析Scroller

Scroller的原理:Scroller並不直接實現View的滑動,它需要配合View的computeScroll()方法。在computeScroll()中不斷讓View進行重繪,每次重繪都會計算滑動持續的時間,根據這個持續時間就能算出這次View滑動的位置,我們根據每次滑動的位置調用scrollTo()方法進行滑動,這樣不斷地重復上述過程就形成瞭彈性滑動。

View的事件分發機制

Activity構成

一個Activity包含一個Window對象,這個對象是由PhoneWindow來實現的。PhoneWindow將DecorView作為整個應用窗口的根View,而這個DecorView又將屏幕劃分為兩個區域:一個是TitleView,另一個是ContentView,而我們平常做應用所寫的佈局正是展示在ContentView中。

源碼解析View的事件分發機制

當我們點擊屏幕時,就產生瞭點擊事件,這個事件被封裝成瞭一個類:MotionEvent。而當這個MotionEvent產生後,那麼系統就會將這個MotionEvent傳遞給View的層級,MotionEvent在View中的層級傳遞過程中就是點擊事件分發。點擊事件有三個重要方法,如下:

dispatchTouchEvent(MotionEvent ev)——用來進行事件分發。

onInterceptTouchEvent(MotionEvent ev)——用來進行事件的攔截,在dispatchTouchEvent()中調用,需要註意的是View沒有提供該方法。

OnTouchEvent(MotionEvent ev)——用來處理點擊事件,在dispatchTouchEvent()方法中進行調用。

View的事件分發機制

當點擊事件產生後,事件首先會傳遞給當前的Activity,這會調用Activity的dispatchTouchEvent()方法,具體的事件處理工作交給DecorView,之後再由DecorView將事件處理工作交給根ViewGroup。

View的工作流程

View的工作流程,指的就是measure、layout和draw。其中measure用來測量View的寬和高,layout用來確定View的位置,draw則用來繪制View。
一個Activity包含一個Window對象,這個對象是由PhoneWindow來實現的。PhoneWindow將DecorView作為整個應用窗口的根View,通過ViewRootImpl的setView方法將DecorView加載到Window中。此外,通過ViewRootImpl的PerformTraveals使得ViewTree開始View的工作流程,方法內部分別執行performMeasure、performLayout和performDraw,在其方法的內部又分別調用View的measure、layout和draw方法。

自定義View

自定義View分為自定義View、自定義ViewGroup和自定義組合控件三大類。其中自定義View又分為繼承系統控件(比如TextView)和繼承View兩種。自定義ViewGroup也分為繼承ViewGroup和繼承系統特定的ViewGroup(比如RelativeLayout)。而自定義組合控件就是多個控件組合起來成為一個新的控件,主要用於解決多次重復使用同一類型的佈局。比如頂部標題欄及彈出的固定樣式的Dialog,這些都是常用的,所以把它們所需要的控件組合起來重新定義成一個新的控件。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *