Previous This paper explains the initialization steps of custom control, and the width and height measurement of custom control.
Override onMeasure method
We get the relevant parameters from the layout file. Now we need to measure the width and height of this control. Rewrite the following method.
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec,heightMeasureSpec); }
Let's talk about the width measurement spec and the height measurement spec first.
The layout we set in the layout file_ Width and layout_ The height dimension data is encapsulated into the width measurement spec and the height measurement spec respectively. It consists of two parts.
int is 32, where 0-29 bits encapsulate the specific size value (number of pixels) and 30-31 bits encapsulate the mode.
There are three modes, EXACTLY, AT_MOST and UNSPECIFIED
Exact: use specific dimension value (such as 10dp) or match_parent
AT_MOST: using wrap_content
UNSPECIFIED: the parent layout does not require the size of this control. Please refer to this article article
Two examples.
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="hello world"/> <Button android:layout_width="100px" android:layout_height="50px"/>
In onMeasure, the width of TextView is 0, the width mode is exact, the height is a fixed value, and the height mode is AT_MOST.
The Button has a width of 100, a width mode of 50, and a height mode of 50.
Through these two examples, we can understand EXACTLY and at_ The most difference. So how to get the dimensions and patterns? Through MeasureSpec.getSize Methods and MeasureSpec.getMode Method acquisition
int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec);
Then determine the width and height of the control according to the requirements, as follows is a common template.
int widht; int height; if(widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST){ //Wrap width and height_ content width = ... height = ... ... }else if(widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.AT_MOST){ //Width is specific size or match_parent, high is wrap_content width = ... height = ... ... }else if(widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.EXACTLY){ //Width and height are specific dimensions or match_parent width = ... height = ... ... }else{ width = ... height = ... ... }
After calculating the width and height values, they can call the setMeasuredDimension method to complete the preliminary measurement of dimensions, as follows.
setMeasuredDimension(width,height);
Why is it a preliminary measurement? Because onMeasure only measures the width and height of the control itself. If you are writing a custom container, you need to consider the width and height of the child controls and their placement in the container (here, you need to override the onLayout method). However, since WaveLoadingView is not a container, you don't need to consider so much.
Finally, let's see what WaveLoadingView's onMeasure has done.
onMeasure method of WaveLoadingView
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int elementWidth = 0; int elementHeight= 0; switch(mType){ case IMAGE_TYPE_TEXT: elementWidth = mTextWidth; elementHeight = mTextHeight; break; case IMAGE_TYPE_CIRCLE: case IMAGE_TYPE_SQUARE: case IMAGE_TYPE_RECT: case IMAGE_TYPE_NOISE: elementWidth = elementHeight = mImageSize; break; case IMAGE_TYPE_CUSTOM: elementWidth = elementHeight = mImageSize; break; } onMeasureSelf(widthMeasureSpec,heightMeasureSpec,elementWidth,elementHeight); }
First of all, the display mode of WaveLoadingView is obtained here, and the width and height of elements are determined according to the mode. The elements here refer to small squares or characters. Each small square or character is an element.
Then take a look at what the onMeasureSelf method does.
protected void onMeasureSelf(int widthMeasureSpec, int heightMeasureSpec,int elementWidth,int elemwntHeight){ //1 int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); //2 int paddingLeft = getPaddingLeft(); int paddingRight = getPaddingRight(); int paddingTop = getPaddingTop(); int paddingBottom = getPaddingBottom(); //3 int wrapWidth = mLength * elementWidth + (mLength - 1) * mInterval + paddingLeft + paddingRight; //4 int waveHeight = (mWaveLength % 2) != 0 ? (int) (elemwntHeight + (mWaveLength / 2 + 1) * elemwntHeight * mWaveOffset) : (int) (elemwntHeight + mWaveLength / 2 * elemwntHeight * mWaveOffset); int wrapHeight = waveHeight + paddingTop + paddingBottom; if(widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST){ width = wrapWidth; height = wrapHeight; }else if(widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.AT_MOST){ height = wrapHeight; }else if(widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.EXACTLY){ width = wrapWidth; } //5 setMeasuredDimension(width,height); }
Wave loading view recommends that you write wrap in both width and height when you use it_ content.
Note 1 the following four lines of code get the width and height values and their patterns, just mentioned above.
Note 2 the following four lines of code get the inner space of the control, that is, in the layout file android:paddingRight , android:paddingLeft , android:paddingTop and android:paddingBottom , in pixels.
Code 3 calculate wrap_ The width under content, mLength refers to the number of elements, and the calculated dimensions can be seen in the following diagram.
Code 4 calculate wrap_ The height under content, as explained here, mWaveLength refers to the number of elements occupied by the wave, and mLength refers to the total number of elements displayed, as shown in the following figure mWaveLength=5, mLength=11.
The calculation is completed. Finally, the calculation result onMeasure is set in code 5.
last
Limited to the length of the article, the article only pasted the key code, and friends who want to know more about the measurement process of this control can go to Github project Read the full code on.