欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

View与LayoutParams如何建立关系

程序员文章站 2022-10-26 18:27:44
知识点整理1. LayoutParams2. MarginLayoutParams3 LayoutParams与View如何建立联系4 自定义LayoutParams4.1 创建自定义属性4.2 继承MarginLayout4.3 重写ViewGroup中几个与LayoutParams相关的方法5 LayoutParams常见的子类1. LayoutParamsLayoutParams翻译过来就是布局参数,子View通过LayoutParams告诉父容器(ViewGroup)应该如何放置自己。从这个定...



1. LayoutParams

LayoutParams翻译过来就是布局参数,子View通过LayoutParams告诉父容器(ViewGroup)应该如何放置自己。
从这个定义中也可以看出来LayoutParams与ViewGroup是息息相关的,因此脱离ViewGroup谈LayoutParams是没
有意义的。
事实上,每个ViewGroup的子类都有自己对应的LayoutParams类,典型的如LinearLayout.LayoutParams和
FrameLayout.LayoutParams等,可以看出来LayoutParams都是对应ViewGroup子类的内部类。

2. MarginLayoutParams

MarginLayoutParams
MarginLayoutParams是和外间距有关的。事实也确实如此,和LayoutParams相比,MarginLayoutParams只是增加了对上下左右外间距的支持。实际上大部分LayoutParams的实现类都是继承自MarginLayoutParams,因为基本所有的父容器都是支持子View设置外间距的

  • 属性优先级问题 MarginLayoutParams主要就是增加了上下左右4种外间距。在构造方法中,先是获取了margin属性;如果该值不合法,就获取horizontalMargin;如果该值不合法,再去获取leftMargin和rightMargin属性(verticalMargin、topMargin和bottomMargin同理)。我们可以据此总结出这几种属性的优先级.
margin > horizontalMargin和verticalMargin > leftMargin和RightMargin、topMargin和bottomMargin 
  • 属性覆盖问题 优先级更高的属性会覆盖掉优先级较低的属性。此外,还要注意一下这几种属性上的注释
Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value 

3 LayoutParams与View如何建立联系

  • 在XML中定义View
  • 在Java代码中直接生成View对应的实例对象
    addView
/**
* 重载方法1:添加一个子View
* 如果这个子View还没有LayoutParams,就为子View设置当前ViewGroup默认的LayoutParams
*/ public void addView(View child) { addView(child, -1); } /**
* 重载方法2:在指定位置添加一个子View
* 如果这个子View还没有LayoutParams,就为子View设置当前ViewGroup默认的LayoutParams
* @param index View将在ViewGroup中被添加的位置(-1代表添加到末尾)
*/ public void addView(View child, int index) { if (child == null) { throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup"); } LayoutParams params = child.getLayoutParams(); if (params == null) { params = generateDefaultLayoutParams();// 生成当前ViewGroup默认的LayoutParams if (params == null) { throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null"); } } addView(child, index, params); } /**
* 重载方法3:添加一个子View
* 使用当前ViewGroup默认的LayoutParams,并以传入参数作为LayoutParams的width和height
*/ public void addView(View child, int width, int height) { final LayoutParams params = generateDefaultLayoutParams(); // 生成当前ViewGroup默认的 LayoutParams
  params.width = width; params.height = height; addView(child, -1, params); } /**
* 重载方法4:添加一个子View,并使用传入的LayoutParams
*/ @Override public void addView(View child, LayoutParams params) { addView(child, -1, params); } /**
* 重载方法4:在指定位置添加一个子View,并使用传入的LayoutParams
*/ public void addView(View child, int index, LayoutParams params) { if (child == null) { throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup"); } // addViewInner() will call child.requestLayout() when setting the new LayoutParams // therefore, we call requestLayout() on ourselves before, so that the child's request // will be blocked at our level requestLayout(); invalidate(true); addViewInner(child, index, params, false); } private void addViewInner(View child, int index, LayoutParams params, boolean preventRequestLayout) { ..... if (mTransition != null) { mTransition.addChild(this, child); } if (!checkLayoutParams(params)) { // ① 检查传入的LayoutParams是否合法 params = generateLayoutParams(params); // 如果传入的LayoutParams不合法,将进行转化操作 } if (preventRequestLayout) { // ② 是否需要阻止重新执行布局流程 child.mLayoutParams = params; // 这不会引起子View重新布局(onMeasure->onLayout- >onDraw) } else { child.setLayoutParams(params); // 这会引起子View重新布局(onMeasure->onLayout- >onDraw) } if (index < 0) { index = mChildrenCount; } addInArray(child, index); // tell our children if (preventRequestLayout) { child.assignParent(this); } else { child.mParent = this; } ..... } 

4 自定义LayoutParams

4.1 创建自定义属性

<resources> <declare-styleable name="xxxViewGroup_Layout"> <!-- 自定义的属性 --> <attr name="layout_simple_attr" format="integer"/> <!-- 使用系统预置的属性 --> <attr name="android:layout_gravity"/> </declare-styleable> </resources> 

4.2 继承MarginLayout

public static class LayoutParams extends ViewGroup.MarginLayoutParams { public int simpleAttr; public int gravity; public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); // 解析布局属性 TypedArray typedArray = c.obtainStyledAttributes(attrs, R.styleable.SimpleViewGroup_Layout); simpleAttr = typedArray.getInteger(R.styleable.SimpleViewGroup_Layout_layout_simple_attr, 0); gravity=typedArray.getInteger(R.styleable.SimpleViewGroup_Layout_android_layout_gravity, -1); typedArray.recycle();//释放资源 } public LayoutParams(int width, int height) { super(width, height); } public LayoutParams(MarginLayoutParams source) { super(source); } public LayoutParams(ViewGroup.LayoutParams source) { super(source); } } 

4.3 重写ViewGroup中几个与LayoutParams相关的方法

// 检查LayoutParams是否合法 @Override protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { return p instanceof SimpleViewGroup.LayoutParams; } // 生成默认的LayoutParams @Override protected ViewGroup.LayoutParams generateDefaultLayoutParams() { return new SimpleViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); } // 对传入的LayoutParams进行转化 @Override protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return new SimpleViewGroup.LayoutParams(p); } // 对传入的LayoutParams进行转化 @Override public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { return new SimpleViewGroup.LayoutParams(getContext(), attrs); } 

5 LayoutParams常见的子类

在为View设置LayoutParams的时候需要根据它的父容器选择对应的LayoutParams,否则结果可能与预期不一致,
这里简单罗列一些常见的LayoutParams子类:

  • ViewGroup.MarginLayoutParams
  • FrameLayout.LayoutParams
  • LinearLayout.LayoutParams
  • RelativeLayout.LayoutParams
  • RecyclerView.LayoutParams
  • GridLayoutManager.LayoutParams
  • StaggeredGridLayoutManager.LayoutParams
  • ViewPager.LayoutParams
  • WindowManager.LayoutParams

本文地址:https://blog.csdn.net/weixin_41477306/article/details/107298804