Zero, Preface:

1. Once a half-artist, I know the importance and complexity of the pen

In Android, many Paint Settings are basically setXXX,getXXX, and many text related content is in Paint 3. The main configuration of the brush, brush type, brush effects (line effect, color, filter), brush text 4. This article won’t cover all of Paint’s apis yet, but I’ll cover as many as I can

The main one is the set method


1. General configuration of brushes

Public void setAlpha(int a) public void setARGB(int a, int r) public void setARGB(int a, int r, int r) Int g, int b) public void setStrokeWidth(float width) public void setAntiAlias(Boolean aa)// Set antialiasingCopy the code


Two, the pen style:Paint.Style.: [#FILL|STROKE|FILL_AND_STROKE]

/** * @param canvas */ private void testStyle(canvas canvas) {Rect Rect = new Rect(0, 0, 100, 100); mRedPaint.setStrokeWidth(15); canvas.save(); mRedPaint.setStyle(Paint.Style.FILL); canvas.translate(50, 450); canvas.drawRect(rect, mRedPaint); canvas.translate(150, 0); mRedPaint.setStyle(Paint.Style.STROKE); canvas.drawRect(rect, mRedPaint); canvas.translate(150 , 0); mRedPaint.setStyle(Paint.Style.FILL_AND_STROKE); canvas.drawRect(rect, mRedPaint); canvas.restore(); mRedPaint.setStrokeWidth(40); }Copy the code


Three, line cap:Paint.Cap.: [#BUTT|ROUND|SQUARE]

1. Draw the point of the circle: paint.cap.round
/** * @param canvas */ private void drawPos(canvas canvas) {// Set the brush cap mRedPaint.setStrokeCap(Paint.Cap.ROUND); mRedPaint.setStrokeWidth(20); DrawPoint (100, 100, mRedPaint); canvas.drawPoints(new float[]{ 400, 400, 500, 500, 600, 400, 700, 350, 800, 300, 900, 300 }, mRedPaint); }Copy the code

2. Comparison of three kinds of wire caps

/** * Cap type test: Paint.cap.butt, Paint.cap.round, Paint.cap.square * * @param canvas */ private void testOfCap(Canvas canvas) { canvas.save(); canvas.translate(150, 200); // String Cap test: mredpaint.setstrokecap (paint.cap.butt); Canvas. DrawLine (0, 0, 0, 200, mRedPaint); canvas.translate(50, 0); mRedPaint.setStrokeCap(Paint.Cap.ROUND); DrawLine (0, 0, 0, 200, mRedPaint); canvas.translate(50, 0); mRedPaint.setStrokeCap(Paint.Cap.SQUARE); DrawLine (0, 0, 0, 200, mRedPaint); canvas.restore(); }Copy the code


Iv. Line intersection Angle test:Paint.Join.: [#BEVEL|ROUND|MITER]

Note: Only the lines drawn by the path have an intersection effect

/** * Angle test: Paint.join.bevel, paint.join.round, paint.join.miter * * @param canvas */ private void testOfJoin(Canvas canvas) { mRedPaint.setStyle(Paint.Style.STROKE); mRedPaint.setStrokeWidth(40); Path path = new Path(); path.moveTo(30, 0); path.lineTo(0, 100); path.lineTo(100, 100); canvas.save(); canvas.translate(600, 100); mRedPaint.setStrokeJoin(Paint.Join.BEVEL); // Line (default) Canvas. DrawPath (path, mRedPaint); canvas.translate(150, 0); mRedPaint.setStrokeJoin(Paint.Join.ROUND); DrawPath (path, mRedPaint); canvas.translate(150, 0); mRedPaint.setStrokeJoin(Paint.Join.MITER); DrawPath (path, mRedPaint); canvas.restore(); }Copy the code


Paint’s path effect

DashPathEffect(new float[]{a, b, a1, b1… }, offSet)

The first parameter is the length of the implicit line segment, and the second parameter is the offset value. The moving line below is the result of constantly changing the offset: mDashOffSet

/** * @param canvas */ private void dashEffect(canvas) {mEffectPaint = new Paint(mRedPaint); mEffectPaint.setStrokeCap(Paint.Cap.BUTT); / / show 100, hide 50, according to 50, 50, hidden cycle of mEffectPaint. SetPathEffect (new DashPathEffect (new float [] {100, 50, 50, 50}, 0)); Path path = new Path(); path.moveTo(100, 650); path.lineTo(1000, 650); canvas.drawPath(path, mEffectPaint); // Show 100, hide 50, show 60, hide 50, loop, offset: mDashOffSet mEffectPaint.setPathEffect(new DashPathEffect(new float[]{100, 50, 50, 50}, mDashOffSet)); Path pathOffset50 = new Path(); pathOffset50.moveTo(100, 750); pathOffset50.lineTo(1000, 750); canvas.drawPath(pathOffset50, mEffectPaint); }Copy the code

2. Corner of a corner

Animation is the result of constantly changing the size of the rounded corner: mEffectCorner

Rounded line / * * * * * @ param canvas * / private void cornerEffect (canvas canvas) {mEffectPaint. SetPathEffect (new CornerPathEffect(mEffectCorner)); mEffectPaint.setStyle(Paint.Style.STROKE); mEffectPaint.setStrokeWidth(40); Path path = new Path(); path.moveTo(550, 550); path.lineTo(900, 300); path.lineTo(1000, 550); canvas.drawPath(path, mEffectPaint); TempPaint = new Paint(); tempPaint.setStyle(Paint.Style.STROKE); tempPaint.setColor(Color.BLUE); tempPaint.setStrokeWidth(2); tempPaint.setPathEffect(new DashPathEffect(new float[]{20, 20}, 0)); Path helpPath = new Path(); helpPath.moveTo(550, 550); helpPath.lineTo(900, 300); helpPath.lineTo(1000, 550); canvas.drawPath(helpPath, tempPaint); }Copy the code

3. DiscretePathEffect(segment length, offset)

/** * @param canvas */ private void discreteEffect(canvas) {canvas.save(); // Save the canvas state to Canvas.translate (0, 950); // The first parameter: the length of the original path to be cut into segments, the smaller, the more small segments to be cut into // The second parameter: the offset distance of each small segment to be cut into. The larger, the greater the offset distance of each line segment. Path path = new Path(); // Define the starting point of the path. Path.moveto (100, 0); path.lineTo(600, -100); path.lineTo(1000, 0); mEffectPaint.setPathEffect(new DiscretePathEffect(2, 5)); mEffectPaint.setStrokeWidth(2); canvas.drawPath(path, mEffectPaint); canvas.translate(0, 100); mEffectPaint.setPathEffect(new DiscretePathEffect(20, 5)); canvas.drawPath(path, mEffectPaint); canvas.restore(); // Restore the canvas state}Copy the code

4. PathDashPathEffect(path, spacing, offset, style)

The difference between the three styles can be clearly seen in the GIF, which is the result of constantly changing the offset: mDashOffSet

//float phase: float advance; //float phase: float advance; //float phase: float advance; //float phase: float advance; //float phase: float advance; //float phase: float advance; //float phase: float advance; //float phase: float advance; //float phase: float advance; //float phase: float advance; //float phase: float advance; //float phase: float advance; // ---- style. ROTATE represents the transition of the corner by rotating [path point sample]; // ---- style. MORPH means to transition the corner by deformation [waypoint sample]; // ---- style. TRANSLATE refers to the transition of the corner by the displacement of the path point sample.Copy the code
/** * @param canvas */ private void PathDashEffect(canvas canvas) {canvas.save(); canvas.translate(0, 1100); Path path = new Path(); // Define the starting point of the path. Path.moveto (100, 80); path.lineTo(600, -100); path.lineTo(1000, 80); / / deformation transition mEffectPaint. SetPathEffect (new PathDashPathEffect (CommonPath. NStarPath (5, 16, 8), 40, mDashOffSet, PathDashPathEffect.Style.ROTATE)); canvas.drawPath(path, mEffectPaint); canvas.restore(); // Rotate the canvas. Save (); canvas.translate(0, 1200); mEffectPaint.setPathEffect(new PathDashPathEffect( CommonPath.nStarPath(5, 16, 8), 40, mDashOffSet, PathDashPathEffect.Style.MORPH)); canvas.drawPath(path, mEffectPaint); canvas.restore(); // Move the canvas. Save (); canvas.translate(0, 1300); mEffectPaint.setPathEffect(new PathDashPathEffect( CommonPath.nStarPath(5, 16, 8), 40, mDashOffSet, PathDashPathEffect.Style.TRANSLATE)); canvas.drawPath(path, mEffectPaint); canvas.restore(); } /** * @param canvas */ private void discreteEffect(canvas) {canvas.save(); // Save the canvas state to Canvas.translate (0, 950); // The first parameter: the length of the original path to be cut into segments, the smaller, the more small segments to be cut into // The second parameter: the offset distance of each small segment to be cut into. The larger, the greater the offset distance of each line segment. Path path = new Path(); // Define the starting point of the path. Path.moveto (100, 0); path.lineTo(600, -100); path.lineTo(1000, 0); mEffectPaint.setPathEffect(new DiscretePathEffect(2, 5)); mEffectPaint.setStrokeWidth(2); canvas.drawPath(path, mEffectPaint); canvas.translate(0, 100); mEffectPaint.setPathEffect(new DiscretePathEffect(20, 5)); canvas.drawPath(path, mEffectPaint); canvas.restore(); // Restore the canvas state}Copy the code
N-angle star path encapsulation:
/** * @param num @param R radius @param R radius @param R radius @param R radius @return nStarPath */ public static Path nStarPath(int) num, float R, float r) { Path path = new Path(); float perDeg = 360 / num; float degA = perDeg / 2 / 2; float degB = 360 / (num - 1) / 2 - degA / 2 + degA; path.moveTo( (float) (Math.cos(rad(degA + perDeg * 0)) * R + R * Math.cos(rad(degA))), (float) (-Math.sin(rad(degA + perDeg * 0)) * R + R)); for (int i = 0; i < num; i++) { path.lineTo( (float) (Math.cos(rad(degA + perDeg * i)) * R + R * Math.cos(rad(degA))), (float) (-Math.sin(rad(degA + perDeg * i)) * R + R)); path.lineTo( (float) (Math.cos(rad(degB + perDeg * i)) * r + R * Math.cos(rad(degA))), (float) (-Math.sin(rad(degB + perDeg * i)) * r + R)); } path.close(); return path; } public static float rad(float deg) {return (float deg) (deg * math.pi /) {return (float deg) {return (float deg) (deg * math.pi /) 180); }Copy the code

5. Overlay effects: PathDashPathEffect(E1, E2…) (Demo here: Discrete effect + sample effect)

/** * @param Canvas */ private void composeEffect(Canvas) {mEffectPaint. SetStyle (Paint. mEffectPaint.setStrokeWidth(40); canvas.save(); canvas.translate(0, 1400); Path path = new Path(); // Define the starting point of the path. Path.moveto (100, 80); path.lineTo(600, -100); path.lineTo(1000, 80); PathDashPathEffect effect1 = new PathDashPathEffect( CommonPath.nStarPath(5, 16, 8), 40, mDashOffSet, PathDashPathEffect.Style.ROTATE); DiscretePathEffect effect2 = new DiscretePathEffect(20, 5); mEffectPaint.setPathEffect(new ComposePathEffect(effect1, effect2)); Canvas. DrawPath (path, mEffectPaint); canvas.restore(); }Copy the code

6. Path stacking

/** * @param canvas */ private void sumEffect(canvas canvas) {canvas.save(); canvas.translate(0, 1500); Path path = new Path(); // Define the starting point of the path. Path.moveto (100, 80); path.lineTo(600, -100); path.lineTo(1000, 80); PathDashPathEffect effect1 = new PathDashPathEffect( CommonPath.nStarPath(5, 16, 8), 40, mDashOffSet, PathDashPathEffect.Style.ROTATE); DiscretePathEffect effect2 = new DiscretePathEffect(20, 5); mEffectPaint.setPathEffect(new SumPathEffect(effect1, effect2)); Canvas. DrawPath (path, mEffectPaint); canvas.restore(); }Copy the code

Shader

A simple class with 5 subclasses:

1. Linear Gradient:
1). New LinearGradient(gradient start x,y, gradient end x,y, gradient 1, gradient 2, gradient mode)

Gradient mode: Shader. TileMode. [MIRROR | CLAMP | REPEAT] (figure in the very image, did not explain)

        int colorStart = Color.parseColor("#84F125");
        int colorEnd = Color.parseColor("#5825F1");
        canvas.save();
        canvas.translate(mCoo.x, mCoo.y);
        mRedPaint.setStyle(Paint.Style.FILL);
        mRedPaint.setShader(
                new LinearGradient(
                        -200, 0, 200, 0,
                        colorStart, colorEnd,
                        Shader.TileMode.MIRROR

                ));
        canvas.drawRect(-400,-200,400,-100,mRedPaint);

        canvas.translate(0, 150);
        mRedPaint.setShader(
                new LinearGradient(
                        -100, 0, 100, 0,
                        colorStart, colorEnd,
                        Shader.TileMode.CLAMP
                ));
        canvas.drawRect(-400,-200,400,-100,mRedPaint);

        canvas.translate(0, 150);
        mRedPaint.setShader(
                new LinearGradient(
                        -100, 0, 100, 0,
                        colorStart, colorEnd,
                        Shader.TileMode.REPEAT
                ));
        canvas.drawRect(-400,-200,400,-100,mRedPaint);
Copy the code


LinearGradient(gradient starting point x,y, gradient end point x,y, color array, position percentage array 0~1, gradient mode)

Int [] colors = new int[]{color.parsecolor ("#F60C0C"),// color.parsecolor ("#F3B913"),// orange Color.parsecolor ("#E7F716"),// yellow color.parsecolor ("#3DF30B"),// green color.parsecolor ("#0DF6EF"),// green Color.parsecolor ("#0829FB"),// blue color.parsecolor ("#B709F4"),// purple}; float[] pos = new float[]{ 1.f / 7, 2.f / 7, 3.f / 7, 4.f / 7, 5.f / 7, 6.f / 7, 1 }; canvas.translate(0, 150); mRedPaint.setShader( new LinearGradient( -300, 0, 300, 0, colors, pos, Shader.TileMode.CLAMP )); canvas.drawRect(-400, -200, 400, -100, mRedPaint);Copy the code

2. RadialGradient
1). Two-color gradient: RadialGradient(Center, radius, color 1, Color 2, Mode)
canvas.translate(mCoo.x, mCoo.y); int colorStart = Color.parseColor("#84F125"); int colorEnd = Color.parseColor("#5825F1"); mRedPaint.setStyle(Paint.Style.FILL); MRedPaint. SetShader (new RadialGradient(0,0,50, colorStart, colorEnd, shader.tilemode.mirror)); canvas.drawCircle(0, 0, 150, mRedPaint); canvas.translate(350, 0); MRedPaint. SetShader (new RadialGradient(0,0,50, colorStart, colorEnd, shader.tilemote.clamp)); canvas.drawCircle(0, 0, 150, mRedPaint); canvas.translate(350, 0); MRedPaint. SetShader (new RadialGradient(0,0,50, colorStart, colorEnd, shader.tilemode.repeat)); canvas.drawCircle(0, 0, 150, mRedPaint);Copy the code


2). Multi-color multi-point radial gradient:

RadialGradient(gradient center, gradient radius, Gradient mode, color array, position percentage array 0~1, Gradient mode)

Int [] colors = new int[]{color.parsecolor ("#F60C0C"),// color.parsecolor ("#F3B913"),// orange Color.parsecolor ("#E7F716"),// yellow color.parsecolor ("#3DF30B"),// green color.parsecolor ("#0DF6EF"),// green Color.parsecolor ("#0829FB"),// blue color.parsecolor ("#B709F4"),// purple}; float[] pos = new float[]{ 1.f / 7, 2.f / 7, 3.f / 7, 4.f / 7, 5.f / 7, 6.f / 7, 1 }; mRedPaint.setStyle(Paint.Style.FILL); mRedPaint.setShader( new RadialGradient( 0, 0, 200, colors, pos, Shader.TileMode.CLAMP )); canvas.drawCircle(0, 0, 250, mRedPaint);Copy the code
3. SweepGradient

This one is a bit simpler than the one above, with no gradient mode

Multi-color scan gradient: SweepGradient(center point x,y, color array, position percentage array 0~1)

int colorStart = Color.parseColor("#84F125"); int colorEnd = Color.parseColor("#5825F1"); mRedPaint.setStyle(Paint.Style.FILL); mRedPaint.setShader( new SweepGradient(0, 0, colorStart, colorEnd)); canvas.drawCircle(0, 0, 150, mRedPaint); canvas.translate(400, 0); Int [] colors = new int[]{color.parsecolor ("#F60C0C"),// color.parsecolor ("#F3B913"),// orange Color.parsecolor ("#E7F716"),// yellow color.parsecolor ("#3DF30B"),// green color.parsecolor ("#0DF6EF"),// green Color.parsecolor ("#0829FB"),// blue color.parsecolor ("#B709F4"),// purple}; float[] pos = new float[]{ 1.f / 7, 2.f / 7, 3.f / 7, 4.f / 7, 5.f / 7, 6.f / 7, 1 }; mRedPaint.setShader( new SweepGradient(0, 0, colors, pos)); canvas.drawCircle(0, 0, 150, mRedPaint);Copy the code
4. Image shader: BitmapShader(image, color mode X, color mode y)

Use all the pixels of the picture as the color of the brush

1). Picture background color of text:
/ / loading pictures, pictures generated shaders Bitmap Bitmap. = BitmapFactory decodeResource (getResources (), R.m ipmap. Menu_bg); BitmapShader bs = new BitmapShader(bitmap, Shader.TileMode.CLAMP,Shader.TileMode.CLAMP); mRedPaint.setShader(bs); mRedPaint.setTextSize(150); mRedPaint.setStrokeWidth(10); mRedPaint.setStyle(Paint.Style.FILL_AND_STROKE); Canvas. DrawText (" Canvas ", 0, 500, mRedPaint);Copy the code

2) Path + image shader to achieve crop image: Path
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.menu_bg);
BitmapShader bs = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mRedPaint.setShader(bs);

mRedPaint.setStyle(Paint.Style.FILL);
Path path = CommonPath.nStarPath(8, 500, 250);
canvas.drawPath(path, mRedPaint);
Copy the code

There is also a ComposeShader that is more complex and will be written in the future if required


Seven, color filter :(the specific principle is the color operation, here all when play to see it, temporarily not deep)

ColorFilter has only three subclasses

1.LightingColorFilter(1, 2) :

Take a look… I don’t speak the

Bitmap mainBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.menu_bg); mRedPaint.setStyle(Paint.Style.FILL); Mredpaint.setcolorfilter (new LightingColorFilter(color.parsecolor ("#FF0000"),// red color.parsecolor ("#0000ff")// blue)); canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint); canvas.translate(350, 0); MRedPaint. SetColorFilter (new LightingColorFilter(color.parsecolor ("#FF0000"),// red color.parsecolor ("#00ff00")// green)); canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint); canvas.translate(350, 0); MRedPaint. SetColorFilter (new LightingColorFilter(color.parsecolor ("#FF0000"),// red color.parsecolor ("#000000")// black)); canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint); canvas.restore();Copy the code
2.PorterDuffColorFilter(color, Mode — porterduff.mode) :

PorterDuff.Mode total 18, in Color will be detailed, here are a few to see

Bitmap mainBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.menu_bg);
mRedPaint.setStyle(Paint.Style.FILL);

mRedPaint.setColorFilter(new PorterDuffColorFilter(
        Color.parseColor("#0000ff"), PorterDuff.Mode.DARKEN));
canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);

canvas.translate(350, 0);
mRedPaint.setColorFilter(new PorterDuffColorFilter(
        Color.parseColor("#0000ff"),PorterDuff.Mode.LIGHTEN
));
canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);

canvas.translate(350, 0);
mRedPaint.setColorFilter(new PorterDuffColorFilter(
        Color.parseColor("#0000ff"),PorterDuff.Mode.SCREEN
));
canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);

canvas.translate(350, 0);
mRedPaint.setColorFilter(new PorterDuffColorFilter(
        Color.parseColor("#0000ff"),PorterDuff.Mode.OVERLAY
));
canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);
Copy the code
3.ColorMatrixColorFilter(colortransform matrix or 20 float numbers)

It happens that the front end time has a little bit of research on the ColorMatrix, so it is used here

Bitmap mainBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.menu_bg); mRedPaint.setStyle(Paint.Style.FILL); // Close the RGB color channel (turn it black), Float [] matrix = new float[]{-1, 0, 0, 0, 0, 255, 0, -1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0}; float[] matrix = new float[]{-1, 0, 0, 0, 0, 0, 0, 1, 0}; ColorMatrix colorMatrix = new ColorMatrix(matrix); mRedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint); canvas.translate(350, 0); // Close the RGB color channel (turn it black), Float [] Matrix2 = new float[]{-1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 255, 0, 0, 0, 0, 1, 0}; ColorMatrix colorMatrix2 = new ColorMatrix(matrix2); mRedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix2)); canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint); canvas.translate(350, 0); // Close the RGB color channel (turn it black), Float [] Matrix3 = new float[]{-1, 0, 0, 0, 255, 0, -1, 0, 255, 0, 0, 0, 255, 0, 0, -1, 255, 0, 0, -1, 255, 0, 0, 0, 1, 0}; ColorMatrix colorMatrix3 = new ColorMatrix(matrix3); mRedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix3)); canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint); canvas.translate(350, 0); Float [] matrix4 = new float[]{float[] matrix4 = new float[]{ R = G = B, // To ensure that the image brightness is constant, R+G+B=1 0.3086f, 0.6094f, 0.0820f, 0, 0, 0.3086f, 0.6094f, 0.0820f, 0, 0, 0.3086f, 0.6094f, 0.0820f, 0, 0, 0, 0, 0, 0 0, 1, 0}; ColorMatrix colorMatrix4 = new ColorMatrix(matrix4); mRedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix4)); canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);Copy the code

Seven, text related

Font. SetTypeface (Typeface. SANS_SERIF); Alignment.settextalign (paint.align.LEFT); Font size.settextSize (100);Copy the code
1. Alignment with built-in font:

Alignment: Paint. The Align. [# LEFT | RIGHT | CENTER]

The built-in font: Typeface. [# DEFAULT | DEFAULT_BOLD | SANS_SERIF | SERIF | MONOSPACE]

canvas.save();
canvas.translate(550, 1600);
mTextPaint.setTypeface(Typeface.SANS_SERIF);
mTextPaint.setTextAlign(Paint.Align.LEFT);
mTextPaint.setTextSize(100);
canvas.drawText("SANS_SERIF", 0, 0, mTextPaint);
Paint tempPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
tempPaint.setStrokeWidth(4);
tempPaint.setColor(Color.RED);
tempPaint.setStyle(Paint.Style.STROKE);
canvas.drawRect(0, - 100, mWinSize.x, 0, tempPaint);

canvas.translate(0, 150);
mTextPaint.setTextAlign(Paint.Align.RIGHT);
mTextPaint.setTypeface(Typeface.SERIF);
canvas.drawText("SERIF", 0, 0, mTextPaint);
canvas.drawRect(0, - 100, mWinSize.x, 0, tempPaint);

canvas.translate(0, 150);
mTextPaint.setTypeface(Typeface.MONOSPACE);
mTextPaint.setTextAlign(Paint.Align.CENTER);
canvas.drawText("MONOSPACE", 0, 0, mTextPaint);
canvas.drawRect(0, - 100, mWinSize.x, 0, tempPaint);

canvas.restore();
Copy the code


2. Create fonts: Place external fonts in assets
/** * Create font * @param canvas */ private void createTypeface(canvas) {mTextPaint. SetTextSize (50); canvas.save(); canvas.translate(50, 1600); mTextPaint.setTypeface(Typeface.MONOSPACE); canvas.drawText("MONOSPACE", 0, 0, mTextPaint); // Canvas. Translate (0, 100); Typeface typeface = Typeface.create(Typeface.MONOSPACE, Typeface.BOLD); mTextPaint.setTypeface(typeface); canvas.drawText("MONOSPACE+BOLD", 0, 0, mTextPaint); // Canvas. Translate (0, 100); Typeface typeface2 = Typeface.create(Typeface.MONOSPACE, Typeface.ITALIC); mTextPaint.setTypeface(typeface2); canvas.drawText("MONOSPACE+ITALIC", 0, 0, mTextPaint); // Canvas. Translate (0, 100); Typeface typeface3 = Typeface.create(Typeface.MONOSPACE, Typeface.BOLD_ITALIC); mTextPaint.setTypeface(typeface3); canvas.drawText("MONOSPACE+BOLD_ITALIC", 0, 0, mTextPaint); // Use the external font canvas.translate(0, 100); Typeface myFont = Typeface.createFromAsset(getContext().getAssets(), "ACHAFSEX.TTF"); mTextPaint.setTypeface(myFont); canvas.drawText("Hello I am Toly", 0, 0, mTextPaint); canvas.restore(); }Copy the code


3. Metrics of words: FontMetrics
1). FontMetrics
public static class FontMetrics { public float top; // public float ascent; // public float leading; public float descent; public float bottom; The bottom} / /Copy the code
2).SERIF font test :(try these properties for different fonts, some fonts vary greatly)

@param canvas */ private void fontMetricsTest(canvas canvas) {canvas.save(); canvas.translate(100, 500); mTextPaint.setTextSize(200); mTextPaint.setTypeface(Typeface.SERIF); canvas.drawText("I am Toly", 0, 0, mTextPaint); / / get the font size Paint. FontMetrics FM = mTextPaint. GetFontMetrics (); Log.e(TAG, "top: " + fm.top); Log.e(TAG, "ascent: " + fm.ascent); Log.e(TAG, "leading: " + fm.leading); Log.e(TAG, "descent: " + fm.descent); Log.e(TAG, "bottom: " + fm.bottom); Paint tempPaint = new Paint(Paint.ANTI_ALIAS_FLAG); tempPaint.setStrokeWidth(1); tempPaint.setColor(Color.RED); tempPaint.setStyle(Paint.Style.STROKE); canvas.drawLine(0, fm.top, mWinSize.x, fm.top, tempPaint); tempPaint.setColor(Color.MAGENTA); canvas.drawLine(0, fm.ascent, mWinSize.x, fm.ascent, tempPaint); tempPaint.setColor(Color.parseColor("#4C17F9")); canvas.drawLine(0, fm.leading, mWinSize.x, fm.leading, tempPaint); tempPaint.setColor(Color.GREEN); canvas.drawLine(0, fm.descent, mWinSize.x, fm.descent, tempPaint); tempPaint.setColor(Color.parseColor("#E74EDD")); canvas.drawLine(0, fm.bottom, mWinSize.x, fm.bottom, tempPaint); canvas.restore(); }Copy the code
The 2018-11-05 21:17:35. 264, 28726-28726 /? E/PaintView: top: -209.57031 2018-11-05 21:17:35.264 28726-28726/? E/PaintView: ascent: -185.54688 2018-11-05 21:17:35.264 28726-28726/? E/PaintView: Leading: 0.0 2018-11-05 21:17:35.264 28726-28726/? Descent: 48.828125 2018-11-05 21:17:35.264 28726-28726/? E/PaintView: bottom: 50.0Copy the code

3). Get the text rectangle
String text = "I am Toly"; Rect textRect = new Rect(); mTextPaint.getTextBounds(text, 0, text.length(), textRect); Log.e(TAG, textRect.toShortString()); // [7,-152][886,49] // draw rectangle tempPaint. SetColor (color.parsecolor ("#66F4F628")); tempPaint.setStyle(Paint.Style.FILL); canvas.drawRect(textRect, tempPaint);Copy the code


4). Deformation operation of text
mTextPaint.setTextScaleX(.5f); / / horizontal scaling mTextPaint. SetStrikeThruText (true); / / delete line mTextPaint setUnderlineText (true); // underline mTextPaint. SetTextSkewX (-.5f); / / tiltCopy the code

So first, there are many not commonly used, after the demand encountered, in the add

Continuation — Update:

1. Set the transition anti-aliasing effect :setFilterBitmap

That’s easy. It’s true/false. The default is false

Bitmap mainBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.menu_bg); Matrix matrix = new Matrix(); matrix.setScale(5, 5); / / amplification matrix mRedPaint. SetFilterBitmap (false); canvas.drawBitmap(mainBitmap, matrix, mRedPaint); canvas.translate(-500, -300); mRedPaint.setFilterBitmap(true); canvas.drawBitmap(mainBitmap, matrix, mRedPaint);Copy the code
2. Add text shadow: setShadowLayer(Blur radius, X offset, Y offset, color)

Note: pictures tried, can not

mRedPaint.setShadowLayer(100, 20, 20, Color.parseColor("#eeF39729")); mRedPaint.setTextSize(400); mRedPaint.setStrokeWidth(10); mRedPaint.setStyle(Paint.Style.FILL); Typeface myFont = TypeFace.createFromasSet (getContext().getAssets(), "chops.ttf "); mRedPaint.setTypeface(myFont); canvas.drawText("Toly", 300, 300, mRedPaint);Copy the code

I tried the shadow effect on the Path, it seems that only the Alpha value works, and the shadow follows the brush color

mRedPaint.setShadowLayer(20, 4, 4, Color.parseColor("#335064F8"));
mRedPaint.setColor(Color.BLUE);
canvas.drawPath(CommonPath.regularStarPath(8, 200),mRedPaint);

canvas.translate(600, 0);
mRedPaint.setShadowLayer(20, 4, 4, Color.parseColor("#885064F8"));
canvas.drawBitmap(mainBitmap, matrix, mRedPaint);
Copy the code

Postscript: Jie wen standard

1. Growth record and Errata of this paper
Program source code The date of note
V0.1, The 2018-11-7 Everything you know and don’t know about Paint on Android
V0.2, The 2018-11-9 Added setFilterBitmap and shadow tests
2. More about me
Pen name QQ WeChat hobby
Zhang Feng Jie te Li 1981462002 zdl1994328 language
My lot My Jane books My CSDN Personal website
3. The statement

1—- This article is originally written by Zhang Fengjie, please note if reproduced

2—- welcome the majority of programming enthusiasts to communicate with each other 3—- personal ability is limited, if there is something wrong welcome to criticize and testify, must be humble to correct 4—- see here, I thank you here for your love and support