Reprint learning from:
http://blog.csdn.net/btt2013/article/details/53447649
Inevitably, projects will encounter the problem of embedded ListView and GridView in ScrollView, which will cause sliding conflicts between controls (ListView/GridView only shows one line); how to solve this problem, the common method is
/**
* Recalculate height
*/
@Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec (Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure (widthMeasureSpec, expandSpec);
}
I know how to use it, but I always know little about its principle. Today I read an article which is very detailed. I hereby reproduce the record.
The original text is as follows:
When customizing View and ViewGroup, we often encounter an int MeasureSpec to represent the size of a component, which contains not only the size of the component, but also the size pattern.
This size model is a little hard to understand. There are three modes of component size in the system:
1. MeasureSpec.EXACTLY
In this mode, the length or width of the component is what the size is.
2. MeasureSpec.AT_MOST
This is also the parent component, can give the largest space, the current component of the maximum length or width can only be so large, of course, can also be smaller than this.
3. MeasureSpec.UNSPECIFIED
That is to say, the current component can freely use space without restriction.
Many people may wonder how an int integer can represent two things (size pattern and size value). We know that there are 32 bits for an int type. There are three modes to represent three states, at least two binary bits. So the system adopts the highest 2-bit representation mode. As shown in the picture:
When the highest two are 00, it means "unspecified mode". MeasureSpec.UNSPECIFIED
When the top two are 01, they mean "exact mode". MeasureSpec.EXACTLY
The top two are "maximum mode" when they are 11. MeasureSpec.AT_MOST
Many people get big when they encounter a bit of operation head. In order to operate easily, the system provides me with a MeasureSpec tool class.
This tool class has four methods and three constants (shown above):
// This is an int variable that contains these two information generated by the size and pattern we gave. Here, the pattern parameter passes one of the three constants.
public static int makeMeasureSpec(int size, int mode)
// This is to get the schema information represented in this variable and compare the values with the three constants.
public static int getMode(int measureSpec)
// This is the value to get the size represented in this variable.
public static int getSize(int measureSpec)
// / Return the pattern and size of this variable into a string for easy logging
public static String toString(int measureSpec)
MeasureSpec.EXACTLY: When we specify the layout_width or layout_height of a control as a specific value, such as andorid:layout_width="50dip", or FILL_PARENT, it is the case that the size of the control has been determined, and it is the exact size.
MeasureSpec.AT_MOST is the largest size. When the layout_width or layout_height of the control is specified as WRAP_CONTENT, the size of the control generally changes with the subspace or content of the control. At this time, the size of the control does not exceed the maximum size allowed by the parent control. Therefore, the mode at this time is AT_MOST, and size gives the maximum allowable size of the parent control.
MeasureSpec.UNSPECIFIED is not specified size, which is not very common. Generally, the parent control is AdapterView, which is the mode passed in through the measure method.
Therefore, when rewriting onMeasure method, size calculation should be carried out according to different modes. The following code is a typical way:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getMeasuredLength(widthMeasureSpec, true), getMeasuredLength(heightMeasureSpec, false));
}
private int getMeasuredLength(int length, boolean isWidth) {
int specMode = MeasureSpec.getMode(length);
int specSize = MeasureSpec.getSize(length);
int size;
int padding = isWidth ? getPaddingLeft() + getPaddingRight()
: getPaddingTop() + getPaddingBottom();
if (specMode == MeasureSpec.EXACTLY) {
size = specSize;
} else {
size = isWidth ? padding + mWave.length / 4 : DEFAULT_HEIGHT
+ padding;
if (specMode == MeasureSpec.AT_MOST) {
size = Math.min(size, specSize);
}
}
return size;
}
Solution to ScrollView Nested ListView and GridView Conflict
public class MyListView extends ListView {
public MyListView(Context context) {
super(context);
}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
public class MyGridView extends GridView {
private boolean haveScrollbar = true;
public MyGridView(Context context) {
super(context);
}
public MyGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Set whether there is a ScrollBar, and when you want to display it in ScollView, set it to false. Default to true
*
* @param haveScrollbars
*/
public void setHaveScrollbar(boolean haveScrollbar) {
this.haveScrollbar = haveScrollbar;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (haveScrollbars == false) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}