preface

  • Custom Views are a must for Android developers; The use of the Path class plays a very important role in custom View rendering
  • There are a lot of articles on the web about the Path class in the custom View, but there are some problems: incomplete content, unclear thinking, simple problems complicated and so on
  • Today, I’m going to give you a comprehensive overview of the use of the Path class in custom Views, which I can assure you is the most comprehensive, clear, and understandable on the market

directory


# 1. Introduction

  • Definition: a path, a line connected by countless points
  • Action: Sets the drawing order & region

Path is only used to describe sequential & fields. Using Path alone has no effect

  • Application scenario: Drawing complex shapes (such as hearts, five-pointed stars, etc.)

The Path class encapsulates geometric paths made up of straight lines and curves (2nd and 3rd degree Bessel curves).


Basis of 2.

2.1 Differences between Open paths and Closed Paths

2.2 How to judge whether a point is inside or outside the graph

  • Judgment methods are divided into odd-even rule & non-zero surround rule, which is described as follows:

  • Example 1 :(parity rule)

From the above picture:

  • The ray emitted by P1 intersects the graph at 1 point, that is, the odd point, so p1 is in the graph

  • The rays from P2 intersect the graph at 2 points, even points, so p2 is in the graph

  • Example 2 :(non-zero circle number rule)

According to the analysis of the above method, any graph is composed of lines connected by points and has direction. See the following figure :(the rectangle is clockwise)

  • The ray emitted by P1 intersects the graph at 1 point, and the right side of the rectangle is radiated from left to right. The number of circles is -1, and the final number of circles is -1, so P1 is inside the graph.
  • P2 emits rays that intersect the graph at two points: the right side of the rectangle radiates from left to right

Number of circles -1; The bottom side of the rectangle is shot from right to left, and the number of circles is +1, and the number of circles is 0. So P2 is outside the graph


3. Specific use

3.1 Object Creation

// the default starting point of Path is (0,0) Path = new Path(); // Special attention: create the global Path object, in onDraw() to modify as needed; Try not to create new objects in the onDraw() method // reason: If the View refreshes frequently, objects will be created frequently, slowing the refresh rate.Copy the code

Because the methods of the Path class are used in combination, the following sets of methods are introduced. Set path to moveTo (), setLastPoint (), lineTo (), close()

// The path will draw moveTo(float x, float y) from that point; // The current point (the point where the last operation ended) is connected to the point // The default point is the origin of the coordinates if no operation has been done. LineTo (float x, float y); Close (); // Close (); // Close ();Copy the code
  • You can useSetLastPoint ()Sets the current point position (insteadMoveTo ())
  • Differences between the two:

Example introduction :(includingSetLastPoint ()withMoveTo ())

// use moveTo () // the default starting point is (0,0) // join point (400,500) path.lineto (400,500); // Move the current point to (300, 300) path.moveto (300, 300); // join point (900, 800) path.lineto (900, 800); Path.close (); path.close(); path.close(); DrawPath (path, mPaint1); // Draw canvas. DrawPath (path, mPaint1); // use setLastPoint () // start point defaults to (0,0) // join point (400,500) path.lineto (400,500); // Move the current point to (300, 300) // Affect the previous operation // but do not set this to the new starting point path.setlastPoint (300, 300); // join point (900,800) path.lineto (900,800); // join point (200,700) path.lineto (200,700); Path.close (); // Close (); // Close (); DrawPath (path, mPaint1); // Draw canvas. DrawPath (path, mPaint1);Copy the code

### about resetting the path

  • There are two ways to reset a Path:The reset ()andThe rewind ()
  • The difference lies in:
methods Whether to retain FillType Whether to retain the original data structure
Path. The reset () is no
Path. The rewind () no is
  1. FillTypeAffect the display effect;The data structureAffect reconstruction speed
  2. So the general choicePath. The reset ()

Because of the simplicity, I will not show you too much here.

# Group 2: Add path using addXxx (), arcTo () combination

###2.1 Add basic graphics

  • Action: Adds a basic graphic to a Path Path

Such as circular path, circular path and so on

  • The specific use
Public void addArc (RectF oval, float startAngle, float sweepAngle) // startAngle: // sweepAngle: determine the Angle of the sweep // method 2 // only different from the above method: Public void arcTo (RectF oval, float startAngle, float sweepAngle) // method 3 // forceMoveTo: // true: Draw an arc at the new starting point, do not connect the last point with the starting point of the arc, that is, there is no intersection with the previous path (same as addArc ()) // false: Draw an arc at the new starting point, but connect the end of the previous path to the beginning of the arc, Public void arcTo (RectF oval, float startAngle, float sweepAngle, Boolean forceMoveTo) // Add the circular path // start point: 0 degrees in the positive direction of the x axis // Specifies whether to draw clockwise or counterclockwise :CW is clockwise, AddCircle (float X, float y, float radius, path.direction dir) // Add elliptic Path // where, AddOval (RectF oval, path.direction dir) // Add the rectangle Path // The starting point of the Path becomes the top left corner of the rectangle addRect(RectF rect, Path.Direction dir) // Add rounded rectangle Path addRoundRect(RectF rect, float rx, float ry, path. Direction dir) //Copy the code

Let’s focus on the dir parameter:

Dir = Direction = Direction of the graph, which is an enumeration type:

  • That was clockwise
  • CCW: Counter-clockwise

The direction of the graph affects:

  • Determine the closing order when adding graphics (the recording order of each point)
  • Graphics rendering results (is an important condition for judging graphics rendering)

** The essence of graphic drawing: first draw points, then connect them. ** Therefore, there is a sequence between the points; Clockwise and counterclockwise are used to determine the order of these points.

The following example will illustrate:

// Canvas. Translate (350, 500); // clockwise path.addrect (0, 0, 400, 400, path.direction.cw); // counterclockwise // path.addrect (0,0,400,400, path.direction.ccw); canvas.drawPath(path,mPaint1);Copy the code

As for the starting point of the path that will be affected by adding a graphic path, the following is an example:

// Trace 1 // Move the Canvas coordinate system to the center of the screen canvas.translate(400,500); // the starting point is (0,0), join point (-100,0) path.lineto (-100,0); // join point (-100,200) path.lineto (-100,200); // join point (200,200) path.lineto (200,200); // Close the path.close(); // close the path.close(); // Draw canvas. DrawPath (path,paint); // Track 2 // Move the Canvas coordinate system to the center of the screen canvas.translate(400,500); // the starting point is (0,0), join point (-100,0) path.lineto (-100,0); // draw a circle: center =(0,0), radius =100px // change the starting point of the path =(0,100) (denoted as starting point 2) // change the starting point principle: // the path changes continue at this point path.addcircle (0,0,100, path.direction.ccw); // start from :(0,100), connect (-100,200) path.lineto (-100,200); // Connect (200,200) path.lineTo(200,200); // connect (200,200) to (0,100) path.close(); // Draw canvas. DrawPath (path,paint); // // Please see the following figureCopy the code

AddArc paths (addArc and arcTo)

// add an arc directly to the path // startAngle: Public void addArc (RectF oval, float startAngle, Float sweepAngle) // arcTo // add an arcTo path // Public void arcTo (RectF oval, float startAngle, float sweepAngle) // method 2 // forceMoveTo: // true: Draw an arc at the new starting point, do not connect the last point with the starting point of the arc, that is, there is no intersection with the previous path (same as addArc ()) // false: Draw an arc at the new starting point, but connect the end of the previous path to the beginning of the arc, Public void arcTo (float startAngle, float sweepAngle, Boolean forceMoveTo) public void arcTo (RectF oval, float startAngle, float sweepAngle, Boolean forceMoveTo)Copy the code

See the following example for details

// Add an arc path to a straight path // For easy observation, translate the coordinate system canvas.translate(350, 500); // join (100,100) path.lineTo(50, 200); AddArc (new RectF(200, 200, 300, 300), 0, 180); / / path. ArcTo (oval, 0270, true); ArcTo (new RectF(200, 200, 300, 300), 0, 180); arcTo(new RectF(200, 200, 300, 300); / / path. ArcTo (oval, 0270, false); DrawPath (path, mPaint1); drawPath(path, mPaint1);Copy the code

##2.2 Add path

  • Function: Merges paths

I’m going to add path 1 to path 2

  • The specific use
Public void addPath (Path SRC) public void addPath (Path SRC) public void addPath (Path SRC) public void addPath (Path SRC, float dx, Public void addPath (path SRC, Matrix Matrix) public void addPath (path SRC, Matrix Matrix) // For ease of observation, translate the coordinate system canvas.translate(350, 500); // Create Path object Path pathRect = new Path(); Path pathCircle = new Path(); // Draw a rectangle pathRect.addRect(-200, -200, 200, 200, path.direction.cw); // Draw a circular Path pathCircle.addCircle(0, 0, 100, path.direction.cw); // Move the circular path (0,200) and add it to the rectangular path pathRect.addPath(pathCircle, 0,200); // Draw the merged path Canvas. drawPath(pathRect,mPaint1);Copy the code

### group 3: Determine path attributes

  • The combination isEmpty (), isRect (), isConvex (), set (), and offset () is adopted

  • Specific use:

Public Boolean isEmpty () // Example: path path = new path (); path.isEmpty(); // Return false path.lineto (100,100); Return true // Determine if path is a rectangle // If it is a rectangle, the rectangle information is stored in rect. Public Boolean isRect (RectF rect) // instance path.lineTo(0,400); Path. The lineTo (400400); Path. The lineTo (400, 0); Path. The lineTo (0, 0); RectF rect = new RectF(); boolean b = path.isRect(rect); // rect (); // rect (); Rect. left = 0 // rect.top = 0 // rect.right = 400 // rect.bottom = 400 // Replace the existing Path with the new Path public void set (Path SRC) // Example // Set a rectangular Path Path = new Path(); Path. AddRect (200, 200200200, the path. The Direction. The CW); // Set a circular Path Path SRC = new Path(); The SRC. AddCircle (0,0,100, Path. Direction. The CW); // Replace the circular path with the rectangular path path.set(SRC); // Draw canvas. DrawPath (path,mPaint); Public void offset (float dx, float dy) // Public void offset (float dx, float dy) // Store the path state after translation, Public void offset (float dx, float dy, path DST) // Canvas. Translate (350, 500); // Add a circle to path (center at the origin) path = new path (); path.addCircle(0, 0, 100, Path.Direction.CW); // Shift the Path and store the state after the shift Path DST = new Path(); path.offset(400, 0, dst); // Pan canvas. DrawPath (path, mPaint1); // Draw path // Draw the translated shape with DST (RED) mpaint1.setcolor (color.red); canvas.drawPath(dst,mPaint1);Copy the code

Group 4: Set the path fill color

  • In Android, there are four fill modes, as follows

All encapsulated in the Path class

Fill mode introduce
EVEN_ODD Odd-even rule
INVERSE_EVEN_ODD Anti-even rule
WINDING Non-zero wrapping number rule
INVERSE_WINDING Anti-non-zero wrapping number rule

Keep in mind two filling rules:

From my previous article (1) the basis of custom View – the most easy to understand the principle of custom View series mentioned that the graph is the existence of direction (drawing = join points into line = have connection order).

  • The specific use
// Set the filling rule path.setFillType () // Fillable rule // 1. EVEN_ODD: parity rule // 2. INVERSE_EVEN_ODD: anti-parity rule // 3. WINDING: Non-zero winding rule // 4. INVERSE_WINDING: anti-non-zero winding rule // Understand the odd-even rule and the anti-odd-even rule: filling effect is opposite // Example: For a rectangle, using the parity rule fills the inside of the rectangle, INVERSE parity fills the outside of the rectangle (illustrated below) // Get the current padding rule path.getFillType () // Determine if it is the INVERSE (INVERSE) rule path.isinverseFillType () // Switch filling rules (that is, the switch between the original rules and reverse) path. ToggleInverseFillType ()Copy the code

Example 1 :(parity rule)

// Canvas. Translate (350, 500); // Add a rectangle to Path. AddRect (-200, -200, 200, 200, path.direction.cw); // Set the Path filling mode to the parity rule path.setFillType(path.filltype. EVEN_ODD); // Path.setfillType (path.filltype. INVERSE_EVEN_ODD); DrawPath (path, mPaint1); // Draw canvas. DrawPath (path, mPaint1);Copy the code

Example 2 :(non-zero wrap rule)

// Canvas. Translate (550, 550); // Add a large square to the path // Counterclockwise path.addrect (-400, -400, 400, 400, path.direction.ccw); // Add a small square to the path // clockwise // path.addrect (-200, -200, 200, 200, path.direction.cw); // Set to counterclockwise path.addrect (-200, -200, 200, 200, path.direction.ccw); // Set Path filling mode to non-zero wrap rule path.setFillType(path.filltype.winding); // Set the anti-non-zero winding rule // path.setfillType (path.filltype. INVERSE_WINDING); // drawPath canvas. DrawPath (Path, mPaint1);Copy the code

Group 5: Boolean operations

  • Action: Operation between two paths Path
  • Application scenarios: Use simple graphics to synthesize relatively complex graphics according to specific rules.
  • The specific use
// Method 1 Boolean op (Path Path, path.op op) // Example // Perform Boolean operations on path1 and path2, specified by the second parameter // Store the results to path1. path1.op(path2, Path.Op.DIFFERENCE); // Method 2 Boolean op (Path path1, Path path2, path.op op) // Example // Perform Boolean operations on path1 and path2, specified by the third parameter // Store the results to path3. path3.op(path1, path2, Path.Op.DIFFERENCE)Copy the code

The operation between (the path. Op parameter) is as follows

For example:

// Canvas. Translate (550, 550); // circle 1: center = (0,0), radius = 100 // circle 2: center = (50,0), radius = 100 path1.addcircle (0,0, 100, path.direction.cw); Path2. AddCircle (50, 0100, the Path. The Direction. The CW); // Take the XOR set of two paths path1.op(path2, path.op.xor); DrawPath (path1, mPaint1); // Draw canvas. DrawPath (path1, mPaint1);Copy the code


4. Bezier curve

  • Definition: a mathematical formula for calculating a curve
  • Function: Calculate and represent curves

Any curve can be represented by a Bezier curve

  • Specific usage: Bezier curve can be described by 1 data point and several control points
  1. Data point: the start point and end point of a path;
  2. Control point: determines the bending trajectory of the path;
  3. Bessel curve of order N +1 = n control points;
  4. (Order 1 = a straight line, higher order can be disassembled into multiple low-order curves)

Canvas provides methods to draw second-order and third-order Bessel curves. The following are the specific methods:

QuadTo (float x1, float y1, float x2, float y2) quadTo(float x1, float y1, float x2, float y2) quadTo(float x1, float y1, float x2, float y2) quadTo(float x1, float y1, float x2, float y2) RQuadTo (float x1, float y1, float x2, float y2) // Draw the third order Bezier curve CubicTo (float x1, float y1, float x2, float y2, float x3, float y3) Float x1, float y1, float x2, float y2, float x3, float y3 rCubicTo(float x1, float y1, float y2, float x3, float y3)Copy the code

This is a brief introduction to bezier curves, but you can refer to this article for more details.


5. To summarize

By reading this article, you have a good understanding of how to use the Path class. For more on Android custom Views, stay tuned: Carson takes you to Android


Welcome to attentionCarson takes you through Android blogs

Blog link: juejin.cn/user/252413…


Please give the top/comment a thumbs up! Because your encouragement is the biggest power that I write!