Android 布局参数

示例

每一个ViewGroup(例如LinearLayout,RelativeLayout,CoordinatorLayout等)需要存储关于其孩子的属性信息。关于它的孩子在地下的布置方式ViewGroup。此信息存储在包装类的对象中ViewGroup.LayoutParams。

要包括特定于特定布局类型的参数,请ViewGroups使用类的子ViewGroup.LayoutParams类。

例如

  • LinearLayout 它的 LinearLayout.LayoutParams

  • RelativeLayout 它的 RelativeLayout.LayoutParams

  • CoordinatorLayout 它的 CoordinatorLayout.LayoutParams

  • ...

大多数会ViewGroups重新利用margins为孩子设置的功能,因此他们不ViewGroup.LayoutParams直接子类化,而是子类化ViewGroup.MarginLayoutParams(其本身是的子类ViewGroup.LayoutParams)。


LayoutParams 在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。a的其他属性View直接View相关,并由其View自身处理。

对于TextView:

  • layout_width,layout_height并且layout_gravity将被存储在一个LinearLayout.LayoutParams对象和由所使用的LinearLayout

  • gravity,text并将textColor由其TextView自身使用

对于ImageView:

  • layout_width,layout_height并且layout_weight将被存储在一个LinearLayout.LayoutParams对象和由所使用的LinearLayout

  • background,scaleType并将src由其ImageView自身使用


获取LayoutParams对象

getLayoutParams是一种View's允许检索当前LayoutParams对象的方法。

由于该LayoutParams对象与该封装 直接相关ViewGroup,因此该方法仅在View附加到时才返回非null值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){  // 不要这样做!
                                              // 这可能会产生NullPointerException
            doSomething();
        }
    }
    
    //...
}

如果要依赖于LayoutParams对象,则应改用onAttachedToWindowmethod。

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()在这里不会返回null
            doSomething();
        }
    }

    //...
}


铸造LayoutParams对象

您可能需要使用特定于特定功能的功能ViewGroup(例如,您可能需要以编程方式更改的规则RelativeLayout)。为此,您将需要知道如何正确投射ViewGroup.LayoutParams对象。

LayoutParams为View实际是另一个孩子的对象获取对象时,这可能会造成混淆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对象是直接相关的类型封育 ViewGroup。

铸造不正确

FrameLayout innerLayout = (FrameLayout)findViewById(R.id.inner_layout);
FrameLayout.LayoutParams par = (FrameLayout.LayoutParams) innerLayout.getLayoutParams();
                                          //不正确!这将产生ClassCastException

正确的铸造

FrameLayout innerLayout = (FrameLayout)findViewById(R.id.inner_layout);
LinearLayout.LayoutParams par = (LinearLayout.LayoutParams) innerLayout.getLayoutParams();
                                         //正确!封闭的布局是LinearLayout