Usually when developing the interface of an Android application, the View control is not used directly, but a subclass of the View control is used. For example, if you want to display a piece of text, you can use the TextView control, a subclass of the View control; if you want to display a button, you can use the Button control, a subclass of the View control. Although Android provides many controls inherited from the View class, in actual development, there will be situations that do not meet the needs. In this case, we can implement it through custom controls. The simplest custom control is to create a class that inherits View or its subclasses( app / java / package name / xxx.java ) and rewrite the class’s Construction method.
The example code is as follows:
public class MyView extends View { public MyView(Context context) { super(context); //Methods used in Java code } public MyView(Context context, AttributeSet attrs) { super(context, attrs); //Methods used in XML layout files } protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //This method is used to measure the size. In this method, you can set the width and height of the control itself or its sub-controls. } protected void onDraw(Canvas canvas) { super.onDraw(canvas); //This method is used to draw images } protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); //Used to specify the position of sub-controls in the layout } //Other methods of custom controls }
The public XXX( Context context ) method is a constructor method used in Java files, and the public XXX( Context context , AttributeSet attrs ) method is used in Method used in XML layout files.
1. Implementation method
Since the system’s own controls cannot meet certain styles or functions required, we need to add additional styles and functions by overriding specified methods in custom controls. The three commonly used methods of custom controls are detailed as follows:
1.onMeasure() method
This method is used to measure the size. In this method, you can set the width and height of the control itself or its sub-controls. The specific introduction of the onMeasure() method is as follows:
onMeasure( int widthMeasureSpec , int heightMeasureSpec )
The first parameter widthMeasureSpec in the onMeasure() method means getting the width of the control specified by the parent container, and the second parameter heightMeasureSpec means getting the height of the control specified by the parent container.
The widthMeasureSpec and heightMeasureSpec parameters not only include the attribute values specified by the parent container, but also include the measurement mode of the parent container. The measurement modes are divided into three types. The details are as follows:
EXACTLY: Used when the width and height values of the custom control are set to specific values, such as 100dp, match_parent, etc. At this time, the width and height values of the control are precise dimensions.
AT_MOST: Used when the width and height value of the custom control is wrap_content. At this time, the width and height value of the control is the maximum space value available for the data content in the control.
UNSPECIFIED: Used when the parent container does not specify the width and height of the custom control.
It should be noted that although the parameters widthMeasureSpec and heightMeasureSpec are the width and height specified by the parent container for the control, the control also needs to set the specific width and height through the setMeasureDimension( int i , int i ) method.
2.onDraw() method
This method is used to draw images. The specific introduction of the onDraw() method is as follows:
onDraw( Canvas canvas )
The parameter canvas in the onDraw() method represents the canvas. The Canvas class (canvas) is often used in conjunction with the Paint class (brush), and the Paint class can be used to draw images in the Canvas class.
3.onLayout() method
The onLayout() method is used to specify the position of the child control in the layout. This method is usually overridden in a custom ViewGroup container.
The specific introduction of the onLayout() method is as follows:
onLayout( boolean changed , int left , int top , int right , int bottom )
There are 5 parameters in the onLayout() method. The first parameter changed indicates whether the size and position of the custom control have changed. The remaining 4 parameters left, top, right, and bottom indicate the child control and parent container respectively. The distance between the left and the top; that is, left and parent left, top and parent top, right and parent left, and bottom and parent top.
4.MyView(Context context, AttributeSet attrs) method
Constructor method used in XML layout files
Use context.obtainStyledAttribute(Attribute attrs,R.styleable.~) to obtain a TypeArray type attribute collection.
5.MyView(Context context) method
Constructor methods used in Java files
6.dispatchDraw(Canvas canvas) method
This method is similar to the onDraw() method, both are used for drawing; the difference is that the onDraw() method is called before drawing the sub-control, while the dispatchDraw() method is called after drawing After child control. That is, onDraw()->Draw sub-control->dispatchDraw(). If you want the sub-control to cover the drawing part, use onDraw(); if you want the sub-control to not cover the drawing part, use dispatchDraw().
2. Dimensional measurement (onMeasure() method)
1. Measurement mode
Android views provide three measurement modes:
(1)MeasureSpec.AT_MOST reaches the maximum value, that is, match_parent.
(2)MeasureSpec.UNSPECIFIED is not specified (actually adaptive), that is, wrap_content.
(3)MeasureSpec.EXACTLY Exact size, that is, specific dp value.
2. Get measurement mode
MeasureSpec.getMode( int widthMeasureSpec )
3. Get the actual size
MeasureSpec.getSize( int widthMeasureSpec )
//Example protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //Get measurement mode int widthMode=MeasureSpec.getMode(widthMeasureSpec); //Judge mode if(widthMode==MeasureSpec.EXACTLY){ //The mode is a specific dp value //Get the actual width int widthSize=MeasureSpec.getSize(widthMeasureSpec); Log.d("OK","Set value, actual width:" + widthSize); } else if(widthMode==MeasureSpec.UNSPECIFIED){ //Mode is unspecified (adaptive), wrap_content //Get the actual width int widthSize=MeasureSpec.getSize(widthMeasureSpec); Log.d("OK","Adaptive, actual width:" + widthSize); } else if (widthMode==MeasureSpec.AT_MOST) { //The mode is to reach the maximum value, match_parent //Get the actual width int widthSize=MeasureSpec.getSize(widthMeasureSpec); Log.d("OK","Maximum value, actual width:" + widthSize); } //Reset the width and height of the sub-control based on the actual width and actual height obtained. ... ... }
4.Measure text size
(1)Measure text width
//Create a Paint (brush) object Paint paint=new Paint(); //Set the text size of the brush paint.setTextSize(textSize); //Measure text width paint.measureText(text);
(2)Measure text height
Using the FontMetrics class
Distance property of FontMetrics class:
top The distance between the top of the row and the baseline.
ascent The distance between the top of the character and the baseline.
descent The distance between the bottom of the character and the baseline.
bottom The distance between the bottom of the row and the baseline.
leading Line spacing.
//Create a Paint (brush) object Paint paint=new Paint(); //Set the text size of the brush paint.setTextSize(textSize); //Get the FontMetrics object Paint.FontMetrics fm=paint.getFontMetrics(); //Text height float h=fm.descent-fm.ascent;
3. Sub-control layout (onLayout() method)
Override common methods in onLayout() method:
getChildCount() Get the number of child controls
getChildAt( int index ) Gets the child control of the specified index and returns View
view.getVisibility() Gets the existence status of the control, GONE, TRUE, FALSE
view.getMeasuredHeight() Gets the control height px
view.getMeasuredWidth() Gets the width of the control in px
view.layout( int l , int t , int r , int b ) Set the left and top distances between the border around the control and the parent container, left and parent left, top and parent top, right and parent left, and bottom and parent top.
//Example protected void onLayout(boolean changed, int l, int t, int r, int b) { for (int i=0;i< getChildCount() ;i + + ){ View view= getChildAt(i); if( view.getVisibility() !=GONE){ int width= view.getMeasuredWidth(); int height= view.getMeasuredHeight(); //Reset the sub-control layout position view.layout(~,~,~,~); } } }
Using requestLayout() in other methods will call onLayout() again to redefine the layout.
4. Attributes and XML layout
1. XML layout file of custom control (res/layout/xxx.xml)
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> </RelativeLayout>
2. XML file for setting the attributes of the combined control (res/value/attrs.xml)
<?xml version="1.0" encoding="utf-8"?> <resources> <!--Declaration-style custom control name--> <declare-styleable name="MyView"> <attr name="attrN1" format="string"/> <!--Attribute name Attribute type --> <attr name="attrN2"> <flag name="FLAG_N1" value="1"/> <!--Attribute name Attribute value (this value can only be int) --> <flag name="FLAG_N2" value="1"/> </attr> </attr name="attrN3" format="reference"/> <!--Attribute name Attribute value (resource R.~.~) --> </declare-styleable> </resources>
declare-statement styleable-style attr-attribute flag-identity, flag
format=”reference”The identification type is resource ( R.~.~ )
3. Create a custom combination control class (app/java/package name/xxx.java)
public class MyView extends RelativeLayout { //Inherit existing controls (RelativeLayout, LinearLayout, etc.) private int i; private TextView textView; public MyView(Context context) { super(context); //Constructor for Java files } public MyView(Context context, AttributeSet attrs) { super(context, attrs); //Constructor used in XML layout file getAttrs(context,attrs); setView(context); } private void getAttrs(Context context,AttributeSet attrs){ //Get attribute value TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.MyView); i=typedArray.getInt(R.styleable.MyView_attrN2,1); int id=typedArray.getResourceId(R.styleable.MyView_attrN3,R.~.~); //typedArray.getString typedArray.getBoolean //Recycle typedArray.recycle(); } private void setView(Context context){ LayoutInflater.from(context).inflate(R.layout.myview,this); textView=(TextView) findViewById( ~ ); textView.setText(i); } }
Be sure to recycle TypedArray after obtaining the custom control property value
Use getResourceId() to get the resource ID of type reference
Custom combination controls need to inherit existing controls (RelativeLayout, LinearLayout, etc.)
LayoutInflater.from( context ).inflate( R.layout.myview , this ); The root is this
4. Use custom combination controls
<MyView app:attrN1="testString" app:attrN2="FLAGN1" ... ... />
Custom attribute usage: app: attribute name = ” attribute value ”
5. Note: Custom control classes need to implement methods
public class MyView extends RelativeLayout { public MyView(Context context) { super(context); //Constructor for Java files } public MyView(Context context, AttributeSet attrs) { super(context, attrs); //Constructor used in XML layout file TypedArray ta=context.obtainStyledAttributes(attrs,R.styleable.MyView); LayoutInflater.from(context).inflate(R.layout.myview,this); } protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //This method is used to measure the size. In this method, you can set the width and height of the control itself or its sub-controls. } protected void onDraw(Canvas canvas) { super.onDraw(canvas); //This method is used to draw images } protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); //Used to specify the position of sub-controls in the layout } protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); //This method is used to draw images, similar to the onDraw() method } }