android画布
In this tutorial, we’ll be discussing a very important part of Android i.e. Canvas. It’s a territory which every developer prefers to stay away from. The reason for this tutorial is to make you more aware and at ease with the Android Canvas.
在本教程中,我们将讨论Android的一个非常重要的部分,即Canvas。 这是每个开发人员都希望远离的领域。 本教程的目的是让您更加了解Android画布,并且更加放心。
Android画布 (Android Canvas)
Many times you end up in a scenario where you need to implement a custom View and/or animate it. It can happen that the requirements are so specific that you need to implement it from scratch. Canvas plays a vital role in building such Custom Views.
很多时候,您最终会遇到需要实现自定义视图和/或对其进行动画处理的情况。 需求可能是如此具体,以至于您需要从头开始实施。 画布在构建此类自定义视图中起着至关重要的作用。
A Canvas is a 2D drawing framework that provides us with methods to draw on the underlying Bitmap. A Bitmap acts as the surface over which the canvas is placed. The Paint class is used to provide colors and styles.
Canvas是2D绘图框架,为我们提供了在底层位图上进行绘图的方法。 位图充当画布在其上放置的表面。 Paint类用于提供颜色和样式。
Before we dig deep into Canvas, let’s look at the lifecycle of a Custom View.
在深入研究Canvas之前,让我们看一下Custom View的生命周期。
A Custom View consists of the following commonly used methods:
自定义视图包含以下常用方法:
onMeasure()
onLayout()
onDraw()
Inside onMeasure
we determine the size of the view and its children.
在onMeasure
我们确定视图及其子视图的大小。
Inside onLayout
the size is assigned to the view.
在onLayout
内部,将大小分配给视图。
The onDraw
method is where the canvas is drawn.
onDraw
方法是绘制画布的位置。
A Canvas Object basically comes as a parameter inside the onDraw
method.
画布对象基本上是onDraw
方法中的一个参数。
The invalidate()
method is used to redraw the view. It calls the onDraw method again. Typically, this is used when the text or color or view needs to be updated based on certain events.
invalidate()
方法用于重绘视图。 它再次调用onDraw方法。 通常,当需要根据某些事件更新文本或颜色或视图时,将使用此选项。
The Canvas class contains methods to draw certain shapes just as line, arc, circle, over. Moreover, we can draw complex geometry too using Paths
.
Canvas类包含一些方法来绘制某些形状,例如直线,圆弧,圆形,上方。 此外,我们也可以使用Paths
绘制复杂的几何图形。
We can also draw text or just simply Paint color on the canvas too.
我们也可以在画布上绘制文本或仅绘制颜色。
Let’s look at how to draw basic stuff on Canvas through our sample android studio project.
让我们看看如何通过示例Android Studio项目在Canvas上绘制基本内容。
Android Canvas示例项目结构 (Android Canvas Example Project Structure)

Android Canvas Example Project
Android Canvas示例项目
To create a Path, two methods are important: moveTo()
and lineTo()
.
要创建路径,两个方法很重要: moveTo()
和lineTo()
。
moveTo
takes you to the coordinates you specify on the screen.
moveTo
将您带到您在屏幕上指定的坐标。
lineTo
draws a line from the current position to the one specified.
lineTo
从当前位置到指定位置绘制一条线。
close()
is used to close a path.
close()
用于关闭路径。
画布坐标系如何工作? (How does the Canvas Coordinate System work?)
In the canvas 0,0 is the top left point. As you move horizontally right the x coordinate increases.
As you move vertically down the y coordinate increases in pixels.
在画布中0,0是左上角。 当您向右水平移动时,x坐标会增加。
当您垂直向下移动时,y坐标以像素为单位增加。
Following diagram illustrates the same:
下图说明了相同的内容:

Android Canvas Coordinate System
Android画布坐标系
矩形与矩形 (Rect vs RectF)
Rect object is used to create a rectangle in which each side is specified in integer value.
RectF does the same but in float values.
Rect对象用于创建一个矩形,其中每边均以整数值指定。
RectF进行相同的操作,但使用浮点值。
In the following example, we’ll see how to draw the various shapes and also use Paint to style them.
在下面的示例中,我们将看到如何绘制各种形状以及如何使用Paint对其进行样式设置。
Android Canvas示例代码 (Android Canvas Example Code)
The code for the activity_main.xml
layout is a basic root layout in which we’ll add our Canvas:
activity_main.xml
布局的代码是基本的根布局,我们将在其中添加Canvas:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" />
The code for the MainActivity.java
is given below:
MainActivity.java
的代码如下:
package com.journaldev.androidcanvasbasics;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
public class MainActivity extends AppCompatActivity {
LinearLayout linearLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
linearLayout = findViewById(R.id.linearLayout);
MyView myView = new MyView(this);
linearLayout.addView(myView);
}
}
The MyView class is where we create our Custom View. Let’s finally draw on the Canvas!
MyView类是我们创建自定义视图的地方。 让我们终于在画布上画画!
package com.journaldev.androidcanvasbasics;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.DisplayMetrics;
import android.view.View;
public class MyView extends View {
Paint mPaint, otherPaint, outerPaint, mTextPaint;
RectF mRectF;
int mPadding;
float arcLeft, arcTop, arcRight, arcBottom;
Path mPath;
public MyView(Context context) {
super(context);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.BLUE);
mPaint.setStrokeWidth(5);
mTextPaint = new Paint(Paint.LINEAR_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
mTextPaint.setColor(Color.BLACK);
mTextPaint.setTextSize(pxFromDp(context, 24));
otherPaint = new Paint();
outerPaint = new Paint();
outerPaint.setStyle(Paint.Style.FILL);
outerPaint.setColor(Color.YELLOW);
mPadding = 100;
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) getContext()).getWindowManager()
.getDefaultDisplay()
.getMetrics(displayMetrics);
int screenWidth = displayMetrics.widthPixels;
int screenHeight = displayMetrics.heightPixels;
arcLeft = pxFromDp(context, 20);
arcTop = pxFromDp(context, 20);
arcRight = pxFromDp(context, 100);
arcBottom = pxFromDp(context, 100);
Point p1 = new Point((int) pxFromDp(context, 80) + (screenWidth / 2), (int) pxFromDp(context, 40));
Point p2 = new Point((int) pxFromDp(context, 40) + (screenWidth / 2), (int) pxFromDp(context, 80));
Point p3 = new Point((int) pxFromDp(context, 120) + (screenWidth / 2), (int) pxFromDp(context, 80));
mPath = new Path();
mPath.moveTo(p1.x, p1.y);
mPath.lineTo(p2.x, p2.y);
mPath.lineTo(p3.x, p3.y);
mPath.close();
mRectF = new RectF(screenWidth / 4, screenHeight / 3, screenWidth / 6, screenHeight / 2);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRoundRect(mRectF, 10, 10, otherPaint);
canvas.clipRect(mRectF, Region.Op.DIFFERENCE);
canvas.drawPaint(outerPaint);
canvas.drawLine(250, 250, 400, 400, mPaint);
canvas.drawRect(mPadding, mPadding, getWidth() - mPadding, getHeight() - mPadding, mPaint);
canvas.drawArc(arcLeft, arcTop, arcRight, arcBottom, 75, 45, true, mPaint);
otherPaint.setColor(Color.GREEN);
otherPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(
getLeft() + (getRight() - getLeft()) / 3,
getTop() + (getBottom() - getTop()) / 3,
getRight() - (getRight() - getLeft()) / 3,
getBottom() - (getBottom() - getTop()) / 3, otherPaint);
canvas.drawPath(mPath, mPaint);
otherPaint.setColor(Color.BLACK);
canvas.drawCircle(getWidth() / 2, getHeight() / 2, arcLeft, otherPaint);
canvas.drawText("Canvas basics", (float) (getWidth() * 0.3), (float) (getHeight() * 0.8), mTextPaint);
}
public static float pxFromDp(final Context context, final float dp) {
return dp * context.getResources().getDisplayMetrics().density;
}
}
pxFromDp
method is used to get the pixel equivalent of the dp value passed.
pxFromDp
方法用于获取与传递的dp值等效的像素。
canvas.drawLine(250, 250, 400, 400, mPaint);
simply draws a line from x1 y1 to x2 y2.
canvas.drawLine(250, 250, 400, 400, mPaint);
只需从x1 y1到x2 y2画一条线。
The following code is used to draw a rectangle at the center of the screen.
以下代码用于在屏幕中心绘制一个矩形。
canvas.drawRect(
getLeft() + (getRight() - getLeft()) / 3,
getTop() + (getBottom() - getTop()) / 3,
getRight() - (getRight() - getLeft()) / 3,
getBottom() - (getBottom() - getTop()) / 3, otherPaint);
Inside the drawCircle
method, the first two parameters passed are the coordinates of the center of the circle. The third parameter sets the radius for the circle.
在drawCircle
方法内部,传递的前两个参数是圆心的坐标。 第三个参数设置圆的半径。
clipRect
clips the canvas with the rectangle. The last parameter sets the clipping region style.
clipRect
用矩形clipRect
画布。 最后一个参数设置裁剪区域样式。
Region.Op.DIFFERENCE
sets the Paint on the region between the canvas and the rectangle specified in the clipRect method.
Region.Op.DIFFERENCE
将Paint设置在clipRect方法中指定的画布和矩形之间的区域上。
Inside the drawText
method the two float values set the origin position of the text. We’ve set it at 30 percent from the left and 80 % from the top of the screen.
在drawText
方法内部,两个float值设置文本的原点位置。 我们将其设置为屏幕左侧的30%和屏幕顶部的80%。
An Anti alias flag ensures that the shape is smooth.
反别名标志可确保形状平滑。
How are the different shapes drawn on the canvas positioned relative to each other?
画布上绘制的不同形状如何相对定位?
画布Z顺序 (Canvas Z-Order)
Elements are arranged on top of each other in the order in which they are drawn. Similar to a frame layout based on the z-order.
元素按绘制顺序彼此排列。 类似于基于z顺序的框架布局。
The output of the above application is given below:
以上应用程序的输出如下:

Android Canvas Basics Output 1
Android Canvas基础输出1

Android Canvas Basics Output 2
Android Canvas基础输出2
That brings an end to this tutorial. You can download the project from the link below:
这样就结束了本教程。 您可以从下面的链接下载项目:
翻译自: https://www.journaldev.com/25182/android-canvas
android画布