Introduction to Android | Customize View (Draw Text, Clip Canvas)

One, Customize View Foundation:

1, Brush Paint

Text correlation:

setColor(@ColorInt int color)setpc
setStrokeWidth(float width)Set Brush Thickness
setTextSkewX(float f)Set slant, negative right slant, positive left
setARGB(int a, int r, int g, int b)Set color, a for transparency
setTextSize(float textSize)Set Drawing Text Size
setFakeBoldText(boolean fakeBoldText)Bold or not
setTextAlign(Paint.Align align)Set text alignment, LEFT, CENTER, RIGHT
setUnderlineText(boolean underlineText)Set Underline
setStyle(Style style)Set Brush Style, FILL, STROKE, FILL_ AND_ STROKE setTypeface

Bitmap correlation

setDither(boolean dither)Set up jitter handling
setAlpha(int a)Set Transparency
setAntiAlias(boolean aa)Whether to turn on anti-aliasing
setFilterBitmap()Whether to turn on optimized Bitmap
setColorFilter(ColorFilter filter)Set up color filtering
setMaskFilter(MaskFilter maskfilter)Set up the effect of the filter
setShader(Shader shader)Set image gradient effect
setStrokeJoin(Paint.Join join)Set Image Combination
setXfermode(Xfermode xfermode)Set Image Overlay Effect
setPathEffect(PathEffect effect)Set path effect reset() to restore default settings

2, Path

moveTo() Draw the starting point
lineTo() Draw connected points
close() Form a closed loop

arcTo() arc path
Parameters: Rectangle to generate ellipse, angle to start arc, angle to scan arc, whether to force the start point of arc to be the starting point of drawing

Region region: An arbitrary-shaped enclosed graphic. Use RegionIterator for region intersection filling operations.

3, Canvas

1) Clear the canvas

 * Canvas Clearing Screen
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

2) Draw the canvas background

 * Draw canvas background
//Draw canvas background, argb
canvas.drawARGB(99, 255, 0, 255);
canvas.drawRGB(255, 0, 255);

3) Draw a circle

 * Draw a circle
//Setting the basic properties of a brush
//Set Brush Fill Style
//Fill Inside Only
//Fill in interior and stroke
//Fill only the stroke
//Sets the stroke width in px, which is valid when the fill style is FILL_AND_STROKE
//Use canvas to draw circles
canvas.drawCircle(200, 200, 150, mPaint);
canvas.drawCircle(200, 200, 130, mPaint);

4) Draw Points

 * Draw Points
//Size of points
//Draw point, x-coordinate, y-coordinate
canvas.drawPoint(340, 340, mPaint);

5) Draw straight lines

 * draw a straight line
//Line thickness
//Draw line starting x-coordinate, starting y-coordinate, ending x-coordinate, ending y-coordinate
canvas.drawLine(360, 360, 660, 660, mPaint);

6) Drawing

 * draw rectangle
//Border thickness of rectangle
//Fill rectangular stroke only
//Draw a rectangle, RectF is a rectangle to hold float type, Rect is a rectangle to hold int type, top left and bottom right
mRectF.set(400F, 400F, 450F, 450F);
mRect.set(500, 500, 550, 550);
canvas.drawRect(mRectF, mPaint);
canvas.drawRect(mRect, mPaint);

7) Drawing Text

 * Draw Text
 * setColor(@ColorInt int color) setpc
 * setStrokeWidth(float width) Set Brush Thickness
 * setTextSkewX(float f) Set slant, negative right slant, positive left
 * setARGB(int a, int r, int g, int b) Set color, a for transparency
 * setTextSize(float textSize) Set Drawing Text Size
 * setFakeBoldText(boolean fakeBoldText) Bold or not
 * setTextAlign(Paint.Align align) Set text alignment, LEFT, CENTER, RIGHT setUnderlineText(boolean underlineText) Set underline
 * setStyle(Style style) Set Brush Style, FILL, STROKE, FILL_AND_STROKE setTypeface(Typeface typeface) sets the Typeface object, i.e. font style, including bold, italic, serif, non-serif, etc.
canvas.drawText("Android Stack", 200, 1000, mPaint);

2. Drawing Text

Prepare the base class BaseView and inherit the View class.

public class BaseView extends View {
    static final int LINE_OFFSET = 60;

    protected Paint notePaint = new Paint();
    protected Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    protected Rect textRect = new Rect();

    public BaseView(Context context) {
        this(context, null);

    public BaseView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);

    public BaseView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

Two brushes are prepared in BaseView.

The method of drawing text, canvas.drawText, requires specifying a string, drawing the starting coordinates, and paint ing the brush.

canvas.drawText(text, x, y, textPaint);

The horizontal line along which the y-value of the starting coordinate is located is also called baseline.

Getting Text Boundaries

You can see from the picture that part of the stroke of the text can go beyond the edge line. Like the j at the beginning.

Use the Paint.getTextBounds method to get the boundaries of the text.

textPaint.getTextBounds(onShowText, 0, onShowText.length(), textRect); // Get text Boundary

Draw part of the code above

private void drawBounds(Canvas canvas, float tx, float ty, String onShowText) {
    canvas.drawText(onShowText, tx, ty, textPaint); // Write
    textPaint.getTextBounds(onShowText, 0, onShowText.length(), textRect); // Get text Boundary


    // Left Side Line
    canvas.drawLine(tx, ty - textRect.height() - LINE_OFFSET, tx, ty + LINE_OFFSET, notePaint);

    // Right Side Line
    canvas.drawLine(tx + textRect.width(), ty - textRect.height() - LINE_OFFSET, tx + textRect.width(), ty + LINE_OFFSET, notePaint);

    // Upper Line
    canvas.drawLine(tx - LINE_OFFSET, ty - textRect.height(), tx + textRect.width() + LINE_OFFSET, ty - textRect.height(), notePaint);

    // y - baseline
    canvas.drawLine(tx - LINE_OFFSET, ty, tx + textRect.width() + LINE_OFFSET, ty, notePaint);

Get text size information

The Paint.FontMetrics class is required. It has five properties

topMaximum distance from baseline to top of highest text
ascentRecommended distance of space above baseline when singled spaced
descentRecommended distance of space below baseline when one-line spacing
bottomMaximum distance from baseline to the lowest character
leadingAdditional space recommended between lines of text

Get Paint.FontMetrics using the Paint.getFontMetrics() method.

Paint.FontMetrics fm = textPaint.getFontMetrics();

Note that top and ascent are negative values.

Method of drawing the above diagram

private void drawFontMetrics(Canvas canvas, float x, float y, String text) {
    canvas.drawText(text, x, y, textPaint);
    textPaint.getTextBounds(text, 0, text.length(), textRect);
    Paint.FontMetrics fm = textPaint.getFontMetrics();

    canvas.drawText(String.format(Locale.CHINA, "top:%.2f, bottom:%.2f",, fm.bottom), x, y + notePaint.getTextSize() * 2.5f, notePaint);
    canvas.drawText(String.format(Locale.CHINA, "ascent:%.2f, descent:%.2f, leading:%.2f", fm.ascent, fm.descent, fm.leading), x, y + notePaint.getTextSize() * 4f, notePaint);


    // fm top line
    canvas.drawLine(x - L_BIAS, y +, x + textRect.width() + L_BIAS, y +, notePaint);


    // fm bottom line
    canvas.drawLine(x - L_BIAS, y + fm.bottom, x + textRect.width() + L_BIAS, y + fm.bottom, notePaint);


    // fm ascent line
    canvas.drawLine(x - L_BIAS, y + fm.ascent, x + textRect.width() + L_BIAS, y + fm.ascent, notePaint);


    // fm descent line
    canvas.drawLine(x - L_BIAS, y + fm.descent, x + textRect.width() + L_BIAS, y + fm.descent, notePaint);

Align text in the middle

With this foundation, we can quickly learn how to achieve text "center alignment". Align horizontal or vertical centerlines of text to a point.

For example, draw a planar coordinate system

Draw two axes, then draw the scale and write the value. The numeric text corresponds to the location of the scale. We mainly use Paint.getTextBounds to get the size information of the text and then calculate the appropriate location.

private void drawChart(Canvas canvas) {
    final float x0 = 100;
    final float y0 = 300; // The coordinates of the origin on the canvas
    final float halfLine = 5; // Half the length of the scale

    canvas.drawLine(x0, y0, x0 + 500, y0, notePaint); // Draw the horizontal axis
    canvas.drawLine(x0, y0, x0, y0 - 290, notePaint); // Draw Vertical Axis

    // Draw horizontal scales and numbers
    for (int i = 1; i <= 4; i++) {
        int step = i * 100;
        String n = String.valueOf(step);
        float x = x0 + step;
        canvas.drawLine(x, y0 - halfLine, x, y0 + halfLine, notePaint); // scale

        // Text alignment
        textPaint.getTextBounds(n, 0, n.length(), textRect);
        canvas.drawText(n, x - textRect.width() / 2f, y0 + textRect.height() + halfLine, textPaint);

    // Draw Vertical Scales and Numbers
    for (int i = 1; i <= 2; i++) {
        int step = i * 100;
        String n = String.valueOf(step);
        float y = y0 - step;
        canvas.drawLine(x0 - halfLine, y, x0 + halfLine, y, notePaint); // scale

        // Text alignment
        textPaint.getTextBounds(n, 0, n.length(), textRect);
        canvas.drawText(n, x0 - halfLine * 2 - textRect.width(), y + textRect.height() / 2f, textPaint);

    // Draw Origin 0
    String origin = "0";
    textPaint.getTextBounds(origin, 0, origin.length(), textRect);
    canvas.drawText(origin, x0 - textRect.width(), y0 + textRect.height(), textPaint);

Three, clip the canvas clip path

Use the canvas.clipPath(path) method.

The clipPath method is equivalent to clipping the canvas along a given path. For this purpose, we can make rounded pictures.

Rounded Picture Example

Rounded pictures are a common design. There is no direct way to display rounded pictures in the official Android library. If it's a solid, gradient background, we can use corners of shape s to round corners. This is where clipPath cuts out rounded corners of the canvas before super.onDraw(canvas). A Path needs to be passed in to specify the clipping range.

Create a new RoundImageView class that inherits from AppCompatImageView.

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;

import androidx.appcompat.widget.AppCompatImageView;

public class RoundImageView extends AppCompatImageView {
    private float vw, vh;
    private Path path = new Path();

    private float topLeftR;
    private float topRightR;
    private float botLeftR;
    private float botRightR;

    public RoundImageView(Context context) {
        this(context, null);

    public RoundImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);

    public RoundImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView);
        topLeftR = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_topLeftR, 0);
        topRightR = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_topRightR, 0);
        botLeftR = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_botLeftR, 0);
        botRightR = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_botRightR, 0);

    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        vw = getWidth();
        vh = getHeight();

    protected void onDraw(Canvas canvas) {
        if (vw > topLeftR && vh > topRightR) {
            path.moveTo(topLeftR, 0);
            path.lineTo(vw - topRightR, 0);
            path.quadTo(vw, 0, vw, topRightR);
            path.lineTo(vw, vh - botRightR);
            path.quadTo(vw, vh, vw - botRightR, vh);
            path.lineTo(botLeftR, vh);
            path.quadTo(0, vh, 0, vh - botLeftR);
            path.lineTo(0, topLeftR);
            path.quadTo(0, 0, topLeftR, 0);

TypedArray is used and declare-styleable resources need to be added.

    <declare-styleable name="RoundImageView">
        <attr name="topLeftR" format="dimension" />
        <attr name="topRightR" format="dimension" />
        <attr name="botLeftR" format="dimension" />
        <attr name="botRightR" format="dimension" />

Use this class. Use directly in layout. Four fillet radius parameters are defined. Set solid color for src. Given a picture, the fillet effect is only visible when the picture content touches the view endpoint.

    app:topRightR="8dp" />

    app:topRightR="25dp" />

    app:botLeftR="16dp" />

    app:topLeftR="16dp" />

    app:topLeftR="16dp" />

style definition

<style name="RoundIvCube">
        <item name="android:layout_width">50dp</item>
        <item name="android:layout_height">50dp</item>
        <item name="android:src">#303F9F</item>
        <item name="android:layout_margin">8dp</item>

Run Results

You can see the rounded corners of each graphic. But we can also see jagged teeth. This clipping method does not make smooth rounded corners.

Android Zero Basic Introduction Tutorial Video Reference

Tags: Android

Posted on Wed, 01 Dec 2021 13:14:18 -0500 by jazz_snob