android画布_Android画布

本文详细介绍了Android Canvas的使用,包括其在自定义视图中的重要性,2D绘图框架的工作原理,如画布坐标系、Rect与RectF的区别,以及如何通过示例代码绘制不同形状并使用Paint进行样式设置。同时,解释了Canvas的Z-Order,即元素的绘制顺序决定了它们在屏幕上的堆叠关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.

我们也可以在画布上绘制文本或仅绘制颜色。

Since canvas is drawn on the screen, views that are drawn need to be measured in terms of pixels (px).
由于画布是在屏幕上绘制的,因此绘制的视图需要以像素(px)进行度量。

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 Basics Project

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 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%。

Why is Anti Alias flag needed in Paint? 为什么在Paint中需要使用抗别名标志?
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 Basics Output 1

Android Canvas基础输出1

Android Canvas Basics Output 2

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画布

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值