Android View rendering and practices

Source: Internet
Author: User

Android View rendering and practices
Overview

The drawing process of the entire View tree is expanded in the javasmtraversals () function of the ViewRoot. java class. The execution process of this function is as follows:
-Determine whether to recalculate the View Size (measure)
-Layout)
-Determine whether redrawing is required (draw)
The flowchart is as follows:

Picture from: View rendering process in common technical points for source code parsing of Android open-source projects

In Android, calling invalidate and requestLayout will trigger a series of methods throughout the life cycle of the View,

Picture from: View rendering process in common technical points for source code parsing of Android open-source projects <喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> Calculate the actual size for the entire View tree. The actual size of each View is determined by the parent control and itself. The measure method calls the onMeasure method, the onMeasure method uses setMeasuredDimension (note padding and margin) to set the View size. The ViewGroup subclass needs to override onMeasure to traverse and measure the size of its child views. The measure method is of the final type and cannot be overwritten, the onMeasure method must be rewritten. The whole measurement process is to recursively apply a View to the View tree. Once the measurement is completed, you can use getMeasuredWidth () and getMeasuredHeight () to obtain the custom ViewGroup of its width and height, you only need to implement the measure and layout process MeasureSpec.

A MeasureSpec object consists of size and mode. The MeasureSpec class encapsulates it in an int value to reduce object allocation. The following three modes are available: int type
-UNSPECIFIED
Parent views do not impose any constraints on child views, such as ListView and ScrollView.
-EXACTLY
The parent view specifies an exact size for the Child view. The child view uses the exact value as the size, such as match_parent or the specific value 20dp.
-AT_MOST
The parent view specifies a maximum size for the Child view. The child view must be within this size, for example, wrap_content.

Related Function makeMeasureSpec (int size, int mode) is encapsulated into MeasureSpec getSize (int measureSpec) according to the size and mode values, and the size value getMode (int MeasureSpec) is returned Based on the measureSpec value) return the mode Value Based on the MeasureSpec value. The above three functions are implemented using bitwise operations. The mode uses up to two bits of int, And the size uses the remaining 30 bits. The key part of the code is
Public static class MeasureSpec {private static final int MODE_SHIFT = 30; // the number of shifts is 30 // 32 digits for the int type and 30 digits for the right shift. This attribute indicates the mask value, this operation is used to perform & operations with the size and mode to obtain the corresponding value. Private static final int MODE_MASK = 0x3 <MODE_SHIFT; // shift 30 bits to the right. The value is 00 + (30 bits 0 ), 0x0000 (in hexadecimal notation) public static final int UNSPECIFIED = 0 <MODE_SHIFT; // shift 30 bits to the right with a value of 01 + (30 bits 0 ), 0x1000 (in hexadecimal notation) public static final int EXACTLY = 1 <MODE_SHIFT; // shift 30 bits to the right with a value of 02 + (30 bits 0 ), that is, 0x2000 (in hexadecimal notation) public static final int AT_MOST = 2 <MODE_SHIFT; // create an integer value. The two values in height represent the mode type, the remaining 30 digits indicate the actual values of length or width. It can be WRAP_CONTENT, MATCH_PARENT, or exactly size public static int makeMeasureSpec (int size, int mode) {return size + mode;} // obtain the mode, and public static int getMode (int measureSpec) {return (measureSpec & MODE_MASK);} // get the actual value of length or width, and calculate public static int getSize (int measureSpec) {return (measureSpec &~ MODE_MASK );}}
Layout determines that the onLayout of the child View in the ViewGroup equivalent to the parent View (pay attention to margin and padding) is abstract, and its subclass must realize that the onLayout of the View is empty. At this time, the measurement has been completed, you can use getMeasuredWidth () and getMeasuredHeight () to obtain its width and height. Do not create an object in onDraw or onLayout because these two methods are frequently called.
Here is a summative figure.

Picture from: LayoutParams, the View rendering process in the public technical point of source code parsing for Android open-source projects. It is a subclass of ViewGroup's internal class and has its own subclass of ViewGroup. LayoutParams. For example, ViewGroup owned by RelativeLayout. the child RelativeLayoutParams getLayoutParams () method of LayoutParams obtains the LayoutParams of its parent View type. For example, if the parent control of the view is RelativeLayout, The LayoutParams type is RelativeLayoutParams. the getLayoutParams () method obtains a view named LayoutParams and performs forced conversion, this may cause a strong Conversion error. attributes such as the margin of the custom View must be rewritten in the LayoutParams specified Draw custom View rendering process. The onDraw method custom ViewGroup must be used to Draw the child View in dispatchDraw, the onDraw function should not be rewritten to call the relevant rendering function in the onDraw to draw the invalidate request. If the View Size does not change, the layout process will not be called. Only those that call invalidate () will be re-drawn () if you want to re-paint the View of the method in the UI thread, use the postInvalidate () method requestLayout when the layout changes, such as the direction and size changes, will call this method, it will trigger the measure and layout processes, but will not perform the draw process best practices

The above are both theoretical knowledge and the summative content of many articles. The following describes how to implement a custom View and ViewGroup.

Custom View

In fact, most of the logic of the custom View is on onDraw. onLayout basically does not need to be re-executed, and onMeasure needs to implement the measurement logic.
The following is a simple and useless custom View. its only purpose is to demonstrate onDraw and onMeasure.

Package cn.edu. zafu. sourcedemo; import android. content. context; import android. graphics. canvas; import android. graphics. color; import android. graphics. paint; import android. graphics. rect; import android. util. attributeSet; import android. view. view;/*** Created by lizhangqu on 2015/5/3. */public class CustomView extends View {private Paint paint = null; private Rect rect = null; private int bgColor = Color. parseColor (#673AB7); // specifies the background color. The custom attribute private int minContentWidth = 50; // specifies the minimum content width, excluding the padding private int minContentHeight = 50; // minimum content height, excluding the padding public mmview (Context context) {this (context, null);} public CustomView (Context context, AttributeSet attrs) {this (context, attrs, 0);} public CustomView (Context context, AttributeSet attrs, int defStyleAttr) {super (context, attrs, defStyleAttr); init ();} /* initialize */private void init () {paint = new Paint (); paint. setAntiAlias (true); paint. setDither (true); paint. setColor (bgColor) ;}@ Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {// In fact, all logics can be measured by simply calling the resolveSize function, which is implemented by yourself here, clear your mind // obtain the mode and size int widthMode = MeasureSpec for width and height. getMode (widthMeasureSpec); int heightMode = MeasureSpec. getMode (heightMeasureSpec); int widthSize = MeasureSpec. getSize (widthMeasureSpec); int heightSize = MeasureSpec. getSize (heightMeasureSpec); // The final width and height exist in the two variables: int width; int height; if (widthMode = MeasureSpec. EXACTLY) {// The parent view specifies the size width = widthSize;} else {// The parent view must be within this size. // pay attention to the padding, add the required width = getPaddingLeft () + getPaddingRight () + minContentWidth; if (widthMode = MeasureSpec. AT_MOST) {// if it is AT_MOST, it must be within the range specified by the parent control and take the width = Math in width and widthSize. min (width, widthSize) ;}} if (heightMode = MeasureSpec. EXACTLY) {// The parent view specifies the size of height = widthSize;} else {// The parent view must be within this size. // pay attention to the padding, in addition, the required height = getPaddingTop () + getPaddingBottom () + minContentHeight; if (heightMode = MeasureSpec. AT_MOST) {// if it is AT_MOST, it must be within the range specified by the parent control and take the height = Math in width and widthSize. min (height, heightSize) ;}} setMeasuredDimension (width, height) ;}@ Override protected void onDraw (Canvas canvas) {super. onDraw (canvas); rect = new Rect (getPaddingLeft (), getPaddingTop (), getMeasuredWidth ()-getPaddingRight (), getMeasuredHeight ()-getPaddingBottom ()); // pay attention to the canvas padding when painting. drawRect (rect, paint );}}
Custom Viewgroup

Implement a ViewGroup with a vertical layout sub-View. For the effect, see the code, explanations, and comments.

Package cn.edu. zafu. sourcedemo; import android. content. context; import android. util. attributeSet; import android. view. view; import android. view. viewGroup;/*** Created by lizhangqu on 2015/5/3. */public class CustomViewGroup extends ViewGroup {public CustomViewGroup (Context context) {this (context, null);} public CustomViewGroup (Context context, AttributeSet attrs) {this (context, attrs, 0);} public CustomViewGroup (Context context, AttributeSet attrs, int defStyleAttr) {super (context, attrs, defStyleAttr );} // Override the onLayout abstract method @ Override protected void onLayout (boolean changed, int l, int t, int r, int B) {final int count = getChildCount (); myLayoutParams lp = null; for (int I = 0; I <count; I ++) {View child = getChildAt (I); // obtain the current View lp = (MyLayoutParams) child. getLayoutParams (); // obtain LayoutParams, Which is forcibly converted to MyLayoutParams child. layout (lp. x, lp. y, lp. x + child. getMeasuredWidth (), lp. y + child. getMeasuredHeight (); // call the layout method of the current View for layout} // rewrite onMeasure to implement the measurement logic @ Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {int width = 0; int lastWidth = 0; int height = getPaddingTop (); final int count = getChildCount (); // obtain the number of subviews for (int I = 0; I <count; I ++) {View child = getChildAt (I); // obtain the current subview measureChild (child, widthMeasureSpec, heightMeasureSpec); // measure the subview, you must call MyLayoutParams lp = (MyLayoutParams) child. getLayoutParams (); // obtain LayoutParams width = Math. max (width, child. getMeasuredWidth () + lp. leftMargin + lp. rightMargin); // compare the width of the current View with the previous View. If the width is greater, note that this width contains the margin lp. x = getPaddingLeft () + lp. leftMargin; // sets the lp on the left side of x of the current View. y = height + lp. topMargin; // set the height on the left of y of the current View to height + lp. topMargin + child. getMeasuredHeight () + lp. bottomMargin; // accumulative height} width = width + getPaddingLeft () + getPaddingRight (); // Add the Left and Right padding height = height + getPaddingBottom (); // Add the lower boundary setMeasuredDimension (resolveSize (width, widthMeasureSpec), resolveSize (height, heightMeasureSpec); // set the width and height, the resolveSize method calculates the optimal size based on the size and MeasureSpec} // rewrite the three LayoutParams generation methods @ Override public MyLayoutParams generateLayoutParams (AttributeSet attrs) {return new MyLayoutParams (getContext (), attrs);} // rewrite the three methods for generating LayoutParams @ Override protected MyLayoutParams generatedefalalayoutparams () {return new MyLayoutParams (LayoutParams. WRAP_CONTENT, LayoutParams. WRAP_CONTENT);} // rewrite the three methods for generating LayoutParams @ Override protected MyLayoutParams generateLayoutParams (LayoutParams p) {return new MyLayoutParams (p. width, p. height);} // inherit MarginLayoutParams to implement LayoutParams. x and y represent the public static class MyLayoutParams extends MarginLayoutParams {public int x on the left and top of the control; // left public int y; // public MyLayoutParams (Context context, AttributeSet attrs) {super (context, attrs);} public MyLayoutParams (int w, int h) {super (w, h );}}}

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.