1. 程式人生 > >Android——View寬高的設定和多種獲取寬高的方法、layout_grivaty與grivaty的區別

Android——View寬高的設定和多種獲取寬高的方法、layout_grivaty與grivaty的區別

一、設定控制元件寬高

設定Layout_width/height引發的寬高思考

方式一:

結果不符合預期。

執行結果:

方式二:

結果符合預期。

如下圖:

Android控制元件寬高的規則:  

Android下的控制元件預設沒有寬高,是由父控制元件給其寬高的。

其中一般的view控制元件是由(ViewGroup控制元件:LinearLayout、RelativeLayout 、TableLayout、FrameLayout 、AbsoluteLayou )五大布局給其寬高的。

而像LinearLayout、RelativeLayout等這些最外層的佈局控制元件的寬高是由Android系統的FrameLayout控制元件設定的。可用android-sdk/tools下的工具hierarchyviewer.bat檢視,如下圖:

針對方式一的修改方案,如下程式碼:

執行結果如下:

二、Activity中獲取控制元件的寬高

程式啟動時想要獲取特定檢視元件的尺寸大小,在onCreate中可能無法取到,因為視窗Window物件還沒建立完成,還沒有執行onMeasure 和 onLayout方法,所以,此時getWidth返回值是0。那麼如何或者說何時才能獲取控制元件的大小呢?

方案1:在oncreate方法中, 發一個延遲訊息,在handleMesaage中獲取控制元件寬高。原理就是延時一段時間,等待控制元件測量、佈局完成後再獲取。(雖然有用但不優雅)

   Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case GET_SIZE:
                    int width = listView.getWidth();
                    break;
            }

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_conversation_ui);
        handler.sendEmptyMessageDelayed(GET_SIZE, 500);
    }

方案2:獲得全域性viewTree的觀察者,並新增全域性的layout監聽。原理就是監聽onlayout方法執行完成之後,就可以獲取控制元件大小了。

// 獲得全域性viewTree的觀察者,並新增 全域性的layout監聽
imageView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.
    OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {
      //由於此方法會執行多次,而我們只需要執行一次就可以了,
      //所以,在執行一次的時候,將全域性的layout監聽取消,此處this指的是,內部的匿名物件
      imageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
      int width = imageView.getWidth();
    }

});

方案3:主動通知系統去測量,呼叫measure(0,0)方法 。再用getMeasureWidth就可以得到測量的結果了。

imageView.measure(0, 0);// 主動通知系統去測量
LogUtils.d("========== imageView getMeasuredWidth: "+imageView.getMeasuredWidth());

方案4:重寫Activity的onWindowFocusChanged方法。

在Activity視窗獲得或失去焦點時被呼叫,例如建立時首次呈現在使用者面前;當前Activity被其他Activity覆蓋;當前Activity轉到其他Activity或按Home鍵回到主屏,自身退居後臺;使用者退出當前Activity。以上幾種情況都會呼叫onWindowFocusChanged。

@Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        LogUtils.d("========== imageView getWidth: " + imageView.getWidth());
    }

三、getWidth()與getMeasuredWidth()的區別

從上面程式碼可以看到,獲取控制元件的寬高有時用getWidth()方法,有時用getMeasuredWidth()方法,這兩個方法有什麼區別呢?

getWidth()方法原始碼:

    /**
     * Return the width of the your view.
     *
     * @return The width of your view, in pixels.
     */
    @ViewDebug.ExportedProperty(category = "layout")
    public final int getWidth() {
        return mRight - mLeft;
    }

從原始碼可以看出,getwidth返回的是右邊座標減去左邊座標(也就是控制元件右邊距螢幕Y軸的距離減去控制元件左邊距螢幕Y軸的距離),這要在佈局之後(也就是onLayout()方法執行完之後)才能確定它們的座標。在佈局後(也就是onLayout()方法執行完之後)才能呼叫getwidth來獲取。

總結:getWidth()獲得的寬度是View在設定好佈局後整個View的寬度。 這個寬度是指在容器ViewGroup中,該view的寬度,可稱為:佈局寬度。

getMeasuredWidth()方法原始碼:

    /**
     * Like {@link #getMeasuredWidthAndState()}, but only returns the
     * raw width component (that is the result is masked by
     * {@link #MEASURED_SIZE_MASK}).
     *
     * @return The raw measured width of this view.
     */
    public final int getMeasuredWidth() {
        return mMeasuredWidth & MEASURED_SIZE_MASK;
    }

註釋:return The raw measured width of this view 獲得的是原始的測量寬度。onMeasure()方法執行完之後就可以呼叫該方法獲取。

總結:getMeasuredWidth()是對View上的內容進行測量後得到的View內容佔據的寬度。這個寬度是根據view中的內容決定。可稱為:元件寬度

當然要得到View內容佔據的寬度,前提是你必須在父佈局的onLayout()方法或者此View的onDraw()方法裡呼叫measure(0,0);(measure中的引數的值你自己可以定義),否則你得到的結果和getWidth()得到的結果是一樣的。

比如你定義一個元件的寬50、高50;但是你在佈局檔案中,硬是要把layout_width指定為match_parent(假設只有一個元件),那這個元件的寬度就被拉到全屏了。這時候getWidth()得到的就是佈局寬度。如果要想得到原始寬度,必須呼叫該元件的measure(0,0)方法重新測量 。再用getMeasureWidth就可以得到了。

兩者的使用場合:

getMeasuredWidth:在自定義view重寫onLayout時、在我們用layoutinflater動態載入view後想獲得view的原始寬度時。

getWidth:一般在view已經佈局後呈現出來了,想獲取寬度時

四、layout_grivaty與grivaty

layout_grivaty使用時的注意點:

結果如下圖:

結果如下圖:

區別: