Five custom View LayoutParams

1. LayoutParams

LayoutParams translates to layout parameters, and the child View tells the parent container (ViewGroup) how to place itself through LayoutParams.
It can also be seen from this definition that LayoutParams and ViewGroup are closely related, so it does not
make sense to talk about LayoutParams without ViewGroup .
In fact, each subclass of ViewGroup has its own corresponding LayoutParams class, such as LinearLayout.LayoutParams and
FrameLayout.LayoutParams, etc. It can be seen that LayoutParams is an internal class corresponding to the ViewGroup subclass.

2. MarginLayoutParams

MarginLayoutParams
MarginLayoutParams is related to the outer spacing. This is also true. Compared with LayoutParams, MarginLayoutParams only adds support for the upper, lower, left, and right outer spacing. In fact, most of the implementation classes of LayoutParams are inherited from MarginLayoutParams, because basically all parent containers support the setting of the outer spacing of the child View

  • The attribute priority issue MarginLayoutParams is mainly to increase the 4 kinds of outer spacing, up, down, left, and right. In the construction method, first get the margin attribute; if the value is illegal, get the horizontalMargin; if the value is illegal, get the leftMargin and rightMargin attributes (verticalMargin, topMargin, and bottomMargin are the same). Based on this, we can summarize the priority of these attributes.
margin > horizontalMargin和verticalMargin > leftMargin和RightMargin、topMargin和bottomMargin
  • Attribute coverage issues with higher priority attributes will override lower priority attributes. In addition, pay attention to the comments on these attributes
Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value

3 How to establish a connection between LayoutParams and View

  • Define View in XML
  • Directly generate the instance object addView corresponding to View in the Java code
/**
* 重载方法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 Custom LayoutParams

4.1 Create custom attributes

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

4.2 inherit 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 Rewrite several methods related to LayoutParams in ViewGroup

// 检查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 Common subclasses of LayoutParams

When setting LayoutParams for View, you need to select the corresponding LayoutParams according to its parent container, otherwise the result may be inconsistent with expectations.
Here is a brief list of some common LayoutParams subclasses:

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

Guess you like

Origin blog.csdn.net/weixin_41477306/article/details/107298804