The previous article focused on the measurement process of View. The parent control’s MeasureSpec and the View’s own ‘LayoutParams’ determine the measurement height of the View. MeasureSpec LayoutParams LayoutParams LayoutParams LayoutParams LayoutParams LayoutParams LayoutParams LayoutParams LayoutParams LayoutParams
Start with the concept
LayoutParams, as the name suggests, are layout parameters. And most of us are familiar with this. Every View in our XML file is exposed to a property like layout_xxx, which is essentially a description of the layout parameters. So it’s pretty clear that anything that starts with layout_ is not part of the View, it controls where it’s displayed.
What are the initialization methods for LayoutParams
In general, we put our controls in XML files, even though we sometimes need to “trick” the screen and get instances of LayoutParams directly through methods like view.getLayoutParams (). But just because we’re less exposed doesn’t mean its initialization method isn’t important.
In fact, a View written in code loads about twice as fast as it loads in XML. But in today’s mobile phone configuration is relatively high, we often ignore this way.
Let’s take a look at what constructors viewGroup.layoutParams actually have.
public LayoutParams(Context c, AttributeSet attrs) {
TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
setBaseAttributes(a,
R.styleable.ViewGroup_Layout_layout_width,
R.styleable.ViewGroup_Layout_layout_height);
a.recycle();
}
public LayoutParams(int width, int height) {
this.width = width;
this.height = height;
}
public LayoutParams(LayoutParams source) {
this.width = source.width;
this.height = source.height;
}
LayoutParams() { }
Copy the code
MarginLayoutParams
In addition to the last method we put in MarginLayoutParams for processing, we have three constructors in the ViewGroup. They are responsible for XML processing, for letting the user specify the width and height directly, and for assignment methods like addAll() for collections.
In fact, the ViewGroup subclass’s LayoutParams class has more constructors that you’re interested in browsing the source code for yourself. I’d like to highlight the MarginLayoutParams I mentioned above.
MarginLayoutParams inherits from viewGroup.layoutParams.
public static class MarginLayoutParams extends ViewGroup.LayoutParams {
@ViewDebug.ExportedProperty(category = "layout")
public int leftMargin;
@ViewDebug.ExportedProperty(category = "layout")
public int topMargin;
@ViewDebug.ExportedProperty(category = "layout")
public int rightMargin;
@ViewDebug.ExportedProperty(category = "layout")
public int bottomMargin;
@ViewDebug.ExportedProperty(category = "layout")
private int startMargin = DEFAULT_MARGIN_RELATIVE;
@ViewDebug.ExportedProperty(category = "layout")
private int endMargin = DEFAULT_MARGIN_RELATIVE;
public MarginLayoutParams(Context c, AttributeSet attrs) {
super(a); TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout); setBaseAttributes(a, R.styleable.ViewGroup_MarginLayout_layout_width, R.styleable.ViewGroup_MarginLayout_layout_height);int margin = a.getDimensionPixelSize(
com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
if (margin >= 0) {
leftMargin = margin;
topMargin = margin;
rightMargin= margin;
bottomMargin = margin;
} else {
int horizontalMargin = a.getDimensionPixelSize(
R.styleable.ViewGroup_MarginLayout_layout_marginHorizontal, -1);
// ... something
}
// ... something}}Copy the code
Looking at the code, it becomes clear why the layout_margin attribute overwrites the values of layout_marginLeft and layout_marginRight in XML layouts.
In fact, in fact, most of the container control are directly inherited ViewGroup. MarginLayoutParams instead of ViewGroup. LayoutParams. So we define LayoutParams again remember inheritance ViewGroup. MarginLayoutParams.
Use LayoutParams in your code
Front LayoutParams several construction methods are introduced, with a LinearLayout. Below we LayoutParams to look at the use of simple ways.
val textView1 = TextView(this)
textView1.text = "Do not specify LayoutParams"
layout.addView(textView1)
val textView2 = TextView(this)
textView2.text = "Manually specify LayoutParams"
textView2.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
layout.addView(textView2)
val textView3 = TextView(this)
textView3.text = "Manually pass LayoutParams"
textView3.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams(100.100))
layout.addView(textView3)
Copy the code
Let’s see what addView() does.
public void addView(View child) {
addView(child, -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();
if (params == null) {
throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
}
}
addView(child, index, params);
}
@Override
protected LayoutParams generateDefaultLayoutParams(a) {
if (mOrientation == HORIZONTAL) {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
} else if (mOrientation == VERTICAL) {
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
}
return null;
}
public void addView(View child, int index, LayoutParams params) {
if (DBG) {
System.out.println(this + " addView");
}
if (child == null) {
throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
}
requestLayout();
invalidate(true);
addViewInner(child, index, params, false);
}
private void addViewInner(View child, int index, LayoutParams params,
boolean preventRequestLayout) {
// ...
if(! checkLayoutParams(params)) { params = generateLayoutParams(params); }// ...
}
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LinearLayout.LayoutParams;
}
Copy the code
It looks like the ViewGroup is so elaborate that if we don’t have LayoutParams for the View, the system will set the default LayoutParams for us based on orientation. Even if we set the wrong LayoutParams value before addView(), the system will correct it for us.
Although the system is good enough to help us correct various errors, forcing the wrong LayoutParams after addView() will still result in a ClassCastException.
LayoutParams are important, and every Android developer should try their best to master them. Knowing how the system is written will make it easier to deal with the simple, streaming layout described above.
In fact, Google’s FlexboxLayout works pretty well. Of course, if you use RecyclerView, you can also write a FlowLayoutManager for processing.
The original reference since more ground: blog.csdn.net/yisizhu/art…