LayoutParams

每個 ViewGroup (例如 LinearLayoutRelativeLayoutCoordinatorLayout 等)都需要儲存有關其子項屬性的資訊。關於他們的孩子在這裡鋪設的方式 5。此資訊儲存在包裝類 ViewGroup.LayoutParams 的物件中。

要包含特定佈局型別的引數,ViewGroups 使用 ViewGroup.LayoutParams 類的子類。

例如

大多數 ViewGroups 都重新使用了為孩子設定 margins 的能力,因此他們不直接將 ViewGroup.LayoutParams 子類化,但是他們將 ViewGroup.MarginLayoutParams 子類 (它本身是 ViewGroup.LayoutParams 的子類)。

LayoutParams in xml

LayoutParams 物件是基於膨脹的佈局 xml 檔案建立的。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:layout_gravity="right"
        android:gravity="bottom"
        android:text="Example text"
        android:textColor="@android:color/holo_green_dark"/>

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="@android:color/holo_green_dark"
        android:scaleType="centerInside"
        android:src="@drawable/example"/>

</LinearLayout>

所有以 layout_ 開頭的引數都指定了封閉佈局應該如何工作。當佈局膨脹時,這些引數被包裹在一個合適的 LayoutParams 物件中,Layout 稍後將使用該物件將特定的 View 正確定位在 ViewGroup 內。View 的其他屬性直接與 View 相關,並由 View 本身處理。

對於 TextView

  • layout_widthlayout_heightlayout_gravity 將儲存在 LinearLayout.LayoutParams 物件中並由 LinearLayout 使用
  • gravitytexttextColor 將由 TextView 本身使用

對於 ImageView

  • layout_widthlayout_heightlayout_weight 將儲存在 LinearLayout.LayoutParams 物件中並由 LinearLayout 使用
  • ImageViewscaleTypesrc 將由 ImageView 本身使用

獲取 LayoutParams 物件

getLayoutParams 是一個 View's 方法,允許檢索當前的 LayoutParams 物件。

因為 LayoutParams 物件與封閉的 ViewGroup 直接相關,所以只有當 View 附加到 ViewGroup 時,此方法才會返回非空值。你需要記住,此物件可能始終不存在。特別是你不應該依賴於 View's 建構函式。

public class ExampleView extends View {
    
    public ExampleView(Context context) {
        super(context);
        setupView(context);
    }

    public ExampleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setupView(context);
    }

    public ExampleView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setupView(context);
    }

    private void setupView(Context context) {
        if (getLayoutParams().height == 50){  // DO NOT DO THIS!
                                              // This might produce NullPointerException
            doSomething();
        }
    }
    
    //...
}

如果你想依賴 LayoutParams 物件,你應該使用 onAttachedToWindow 方法代替。

public class ExampleView extends View {

    public ExampleView(Context context) {
        super(context);
    }

    public ExampleView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ExampleView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (getLayoutParams().height == 50) { // getLayoutParams() will NOT return null here
            doSomething();
        }
    }

    //...
}

轉換 LayoutParams 物件

你可能需要使用特定於 ViewGroup 的功能(例如,你可能希望以程式設計方式更改 RelativeLayout 的規則)。為此,你需要知道如何正確地投射 ViewGroup.LayoutParams 物件。

當為一個孩子獲得一個 LayoutParams 物件時,這可能有點令人困惑,這實際上是另一個 ViewGroup

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/outer_layout"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <FrameLayout
        android:id="@+id/inner_layout"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_gravity="right"/>

</LinearLayout>

重要提示: LayoutParams 物件的型別與 ENCLOSING ViewGroup 的型別直接相關。

***** 轉換錯誤* :

FrameLayout innerLayout = (FrameLayout)findViewById(R.id.inner_layout);
FrameLayout.LayoutParams par = (FrameLayout.LayoutParams) innerLayout.getLayoutParams();
                                          // INCORRECT! This will produce ClassCastException

正確轉換

FrameLayout innerLayout = (FrameLayout)findViewById(R.id.inner_layout);
LinearLayout.LayoutParams par = (LinearLayout.LayoutParams) innerLayout.getLayoutParams();
                                         // CORRECT! the enclosing layout is a LinearLayout