“This is the 20th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

Android View and ViewGroup

Do you often see views and viewgroups in custom views? If you are familiar with custom views, you can skip this article. If you just have a preliminary understanding, this article may make you understand some more transparent.

Relationship between

View is a single component, similar to text component, image component, input box component; A ViewGroup is a container, like a linear layout, relative layout, etc. So when you customize a View, it depends on whether you want to customize a group of components, or a single component.

But notice that the parent class of a ViewGroup is a View, so it also has the characteristics of a View and can implement View methods, but it is mainly used as a container for the View.

The custom View

In fact, we usually use components, are a custom View, but the system to help us achieve a good. Let’s look at the implementation of TextView, which also inherits the VIew


public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {

...

}

Copy the code

Let’s implement an adaptive custom VIew text component by mimicking it.

Before we polish the code, let’s take a look at the basic concepts and common methods used in View.

Let’s think about whether we need to know where to draw, how big to draw, and how to draw before we start doodling ourselves, and then understand the following methods with this in mind.

  • OnLayout: Determines the location of components. Called from the layout when this view should assign size and location to each of its children. A derived class with children should override this method and invoke the layout on each of its children.

  • OnMeasure: Determines the size of a component. Measure view and its contents to determine measurement width and measurement height. This method measure(int, int) is called by subclasses and should be overridden by subclasses to provide an accurate and valid measure of their content.

  • OnDraw: What the component looks like. Perform this operation to draw.

Now that we’re all set, we’re ready to draw.

  1. Custom property definitions. Create the attrs.xml file in the value folder

<resources>

<declare-styleable name="MyTextView">

<attr name="myText" format="string" />

<attr name="myTextSize" format="dimension" />

</declare-styleable>

</resources>

Copy the code
  1. Write a custom View to the Layout file
<com.demo.demo.MyTextView Android :layout_width="wrap_content" Android :layout_height="wrap_content" app:myText=" test" app:myTextSize="30sp" android:background="@color/purple_200" />Copy the code
  1. Custom View class
public class MyTextView extends AppCompatTextView { private String text; // Text private int textSize; // Text size private Rect bound; private Paint paint; public MyTextView(Context context) { super(context); } public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); / / get the custom attribute's value TypedArray a = context. ObtainStyledAttributes (attrs, R.s tyleable. MyTextView); text = a.getString(R.styleable.MyTextView_myText); textSize = (int) a.getDimension(R.styleable.MyTextView_myTextSize, 100); a.recycle(); paint = new Paint(); paint.setTextSize(textSize); Bound = new Rect(); Log.d("text:", "text:" + text); paint.getTextBounds(text, 0, text.length(), bound); } public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); WidthMode = MeasureSpec. GetMode (widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); If (widthMode == MeasureSpec.AT_MOST) {wrap_content Rect bounds = new Rect(); paint.getTextBounds(text, 0, text.length(), bounds); widthSize = bounds.width() + getPaddingLeft() + getPaddingRight(); } Else if (widthMode == MeasureSpec.EXACTLY) {} Else if (widthMode == MeasureSpec.UNSPECIFIED) { } if (heightMode == MeasureSpec.AT_MOST) {wrap_content Rect bounds = new Rect(); paint.getTextBounds(text, 0, text.length(), bounds); heightSize = bounds.height() + getPaddingTop() + getPaddingBottom(); } else if (heightMode == MeasureSpec.EXACTLY) {// Specify the exact value in the layout for example :100dp/match_parent} else if (heightMode == EXACTLY) MeasureSpec.UNSPECIFIED) {// As large as possible, setMeasuredDimension(widthSize, heightSize); } @Override protected void onDraw(Canvas canvas) { Paint.FontMetrics fontMetrics = paint.getFontMetrics(); int dy = (int) ((fontMetrics.descent - fontMetrics.ascent) / 2 - fontMetrics.descent); Int BaseLine = getHeight() / 2 + dy; int x = getPaddingLeft(); canvas.drawText(text, x, baseLine, paint); }}Copy the code