第三章 Android控件架構與自定義控件詳解

Android控件架構

在Activity中使用`setContentView(R.layout.activity_main)`來設置一個佈局。

每個Activity都包含一個Window對象,在Android中Window對象通常由PhoneWindow來實現。PhoneWindow將一個DecorView設置整個應用窗口的根View,這裏面所有的View監聽事件,都由WindowMannagerService來進行接收,並通過Activity對象來回調相應的onClickListener。
DecorView將屏幕分爲兩部分,一個是TitleView,一個是ContentView。ContentView是一個ID爲content的Framelayout,activity_main.xml就是設置在這樣一個Framelayout中。
注意:當程序在onCreate()方法中調用setContentView(R.layout.activity_main)的時候,ActivityMannagerService會回調onResume(),此時系統纔會把整個DecorView添加到PhoneWindow中。

View的測量

在測量的時候使用到一個類MeasureSpec,代表一個32位的int值,其中高2位代表測量的模式,低30位代表測量的大小。
測量模式一般是分三種:
AT_MOST:當控件的寬和高屬性給定wrap_content的時候,使用的是該模式。
EXACTLY:當控件的寬和高給定一個具體值的時候,或者指定爲match_parent的時候,系統使用的是該模式。
UNSPECIFIED:父容器不對view有任何限制,要多大就給多大,這種情況一般用於系統內部,表示一種測量的狀態。
自定義View重寫onMeasure()的時候,需要setMeasuredDimension()來設置控件的大小。例如:

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
    }

    private int measureHeight(int heightMeasureSpec) {
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int result = 0;
        switch (heightMode){
            case MeasureSpec.AT_MOST:
                Log.i(TAG, "measureHeight: "+heightMode);
                result = 200;
                result = Math.min(heightSize, result);
                break;
            case MeasureSpec.EXACTLY:
                Log.i(TAG, "measureHeight: "+heightMode);
                result = heightSize;
                break;
        }
        return result;
    }

注意:如果沒有重寫onMeasure()方法,那麼指定控件寬高爲wrap_content無效,系統不知道應該使用多大的尺寸,將默認充滿整個屏幕。

View的繪製

創建一個Canvas的時候,需要傳入一個bitmap:

Canvas canvas = new Canvas(bitmap);//裝載畫布

這個bitmap用來存儲所有繪製在canvas上的像素信息,canvas的drawXXX方法將會作用在這個bitmap上。

   重寫onDraw方法,使用canvas的繪製API,但是其實並沒有將圖形繪製在onDraw()方法指定的那塊畫布上,
而是通過改變bitmap,然後讓View重繪,顯示改變之後的bitmap。

ViewGroup的測量與繪製

測量階段:當ViewGroup的大小爲wrap_content,ViewGroup首先會對子view進行遍歷,獲得子view的大小,然後決定自己的大小。而在其他模式下,則會通過具體的數值來設置自身的大小。
繪製階段:如果沒有指定ViewGroup的背景,那麼onDraw()不會被調用;但是,ViewGroup會使用dispatchDraw()方法來繪製其子view,其過程同樣是通過遍歷所有子view,並調用子view的繪製方法來完成繪製工作。

自定義View

自定義View:
1:重寫onDraw()來繪製View的顯示內容。
2:如果該view使用 wrap_content , 還需要重寫 onMeasure() 。
3:通過自定義attrs屬性,可以設置新的屬性配置值。使用 TypedArray 獲取完屬性的值後,要調用 TypedArray.recycle()

三種方式實現自定義的控件
1:對現有控件進行拓展。
2:通過組合來實現新的控件。(下個鏈接是一個topbar的小案例)

http://blog.csdn.net/ghdsq/article/details/79352111

3:重寫view來實現全新的控件。
(1) 弧形展示圖

http://blog.csdn.net/ghdsq/article/details/79353814

(2) 音頻條形圖

http://blog.csdn.net/ghdsq/article/details/79355944

自定義ViewGroup

自定義ViewGroup:
1:重寫onMeasure()對子View進行測量。
2:重寫onLayout()來確定子view的位置。
3:重寫onTouchEvent()方法增加響應事件。
類似Android原生控件 ScrollView 的自定義 ViewGroup :

http://blog.csdn.net/ghdsq/article/details/79360238

事件攔截機制分析

http://blog.csdn.net/ghdsq/article/details/78985003

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