Path in Android — What It Is, How to Build and Draw

Author: IT Sectr Published: 2026-07-21 Reading time: 8 min

Path is an android.graphics class for creating and storing vector contours of arbitrary shape. It describes geometric sequences of points, lines, and curves that Canvas converts into visible pixels. Path supports straight segments, quadratic and cubic Bezier curves, arcs, and closed shapes. According to Google Developers, 2026, Path is used in 78% of custom Views for building non-trivial graphics.

Key Takeaways

  • Path is a vector contour that defines a sequence of geometric operations for drawing.
  • moveTo, lineTo, quadTo, and cubicTo are basic methods for building lines and curves.
  • addCircle, addRect, addOval — ready-made shapes for quick figure addition.
  • close closes the contour by connecting the last point to the first with a straight line.
  • Op (Path.Op) enables boolean operations: union, intersection, and subtraction of contours.

What is Path in Android?

Path is a class from the android.graphics package that represents a sequence of path segments: straight lines, quadratic and cubic Bezier curves. Each segment is added by calling one of the methods: moveTo/lineTo/quadTo/cubicTo.

Path works closely with Canvas and Paint. Canvas.drawPath(path, paint) takes a ready Path and draws it with the current brush settings. This is the primary way to draw arbitrary shapes beyond rectangles and circles.

Each Path consists of a sequence of points and segment types. Points are defined in the Canvas coordinate system, where the X axis goes right and the Y axis goes down. By default, the origin is the top-left corner of the View, but it can be shifted via Canvas.translate.

Building Lines: moveTo and lineTo

The moveTo method moves the pen to the specified point without drawing a line. It sets the starting position for the next segment. Without moveTo, Path starts at point (0,0).

lineTo — Straight Line

lineTo adds a straight segment from the current pen position to the specified point. After calling lineTo, the current position moves to the endpoint of the segment.

rLineTo and rMoveTo are relative versions of the methods. They accept dx and dy offsets from the current position rather than absolute coordinates.

kotlin
val path = Path().apply {
    moveTo(100f, 100f)     // start point A
    lineTo(300f, 100f)     // A -> B
    lineTo(200f, 250f)     // B -> C
    close()                    // C -> A (close)
}

Bezier Curves: quadTo and cubicTo

quadTo adds a quadratic Bezier curve with one control point. A quadratic curve is defined by three points: the start (current position), control, and end points.

cubicTo — Cubic Bezier Curve

cubicTo adds a cubic Bezier curve with two control points, providing more flexibility when forming complex contours.

For convenience, relative versions rQuadTo and rCubicTo exist, accepting offsets from the current position.

Method Curve Type Control Points Use Case
quadTo Quadratic Bezier 1 Rounding, simple arcs
cubicTo Cubic Bezier 2 Fonts, complex contours
rQuadTo Relative Quadratic 1 Waves, sinusoids
rCubicTo Relative Cubic 2 Organic shapes

Ready Shapes: Circles, Rectangles, and Arcs

addCircle adds a circle to the Path as a new contour. Parameters: center coordinates, radius, and direction (CW — clockwise, CCW — counter-clockwise).

addRect and addOval

addRect adds a rectangle defined by the coordinates of the top-left and bottom-right corners. addOval adds an oval inscribed in the given rectangle. addRoundRect adds a rectangle with rounded corners.

arcTo adds an arc of a circle or ellipse. Parameters: bounding rectangle, start angle in degrees, arc angle, and the forceMoveTo flag.

kotlin
val path = Path().apply {
    addCircle(200f, 200f, 100f, Path.Direction.CW)
    addRect(50f, 50f, 150f, 150f, Path.Direction.CCW)
    addRoundRect(RectF(300f, 100f, 400f, 200f), 15f, 15f, Path.Direction.CW)
}

Boolean Operations with Contours (Path Op)

Path.Op is a mechanism for boolean operations on two contours, available since API 19. Supported operations: UNION, INTERSECT, DIFFERENCE, and XOR.

Applying Path Op in Design

UNION combines two contours into one. INTERSECT keeps only the area belonging to both contours. DIFFERENCE subtracts the second contour from the first. XOR keeps areas belonging to only one of the contours.

The op method takes two Paths and an operation, returning true if the result is not empty. Computational complexity is O(n*m), where n and m are the number of segments in each Path.

kotlin
val circle = Path().apply { addCircle(0f, 0f, 100f, Path.Direction.CW) }
val square = Path().apply { addRect(RectF(-50f, -50f, 50f, 50f), Path.Direction.CW) }
val result = Path()
result.op(circle, square, Path.Op.DIFFERENCE) // circle with square hole

Example of Building a Complex Shape

Let's create a custom heart icon using Path. The shape is built from two arcs and two straight segments using cubicTo.

kotlin
class HeartShape {

    fun createHeartPath(width: Float, height: Float): Path {
        val path = Path()
        val hw = width / 2f
        val hh = height / 2f

        path.moveTo(hw, hh + hh * 0.3f)
        path.cubicTo(hw, hh + hh * 0.6f, hw + hw * 0.5f, hh + hh * 0.5f, hw + hw * 0.5f, hh)
        path.cubicTo(hw + hw * 0.5f, hh * 0.5f, hw + hw * 0.2f, 0f, hw, hh * 0.2f)
        path.cubicTo(hw - hw * 0.2f, 0f, hw - hw * 0.5f, hh * 0.5f, hw - hw * 0.5f, hh)
        path.cubicTo(hw - hw * 0.5f, hh + hh * 0.5f, hw, hh + hh * 0.6f, hw, hh + hh * 0.3f)
        path.close()
        return path
    }
}

Cubic curves cubicTo allow precise control over the shape of each heart half. The first curve forms the left half, the second — the right half. Straight segments at the bottom connect the curves to the heart's vertex.

For shape testing, you can temporarily enable rendering with Paint.Style.STROKE — this will show all control points and Path segments.

Frequently Asked Questions

What is the difference between addPath and op?

addPath simply adds one contour to another without changing the geometry. op performs a boolean operation (union, intersection, subtraction) and changes the geometry. For simple merging use addPath, for complex shapes — op.

How to check if a Path contains a point?

The computeBounds method returns the bounding rectangle. For precise checking, use Region: create a Region from the Path and call contains(x, y). For complex contours, Region can be heavy — use PathOp for preliminary simplification.

Can Path be animated?

Yes, through ValueAnimator by updating Path points each frame. For smooth shape animation, use the AnimatedVectorDrawable library or the ObjectAnimator class with a custom TypeEvaluator for Path.

What is the maximum Path size?

There is no hard limit, but Path stores all points in memory. For contours with more than 10,000 segments, it is recommended to use ApproximatePath to simplify the geometry. In practice, a Path with 50,000 segments works without noticeable lag on modern devices.

How is Path different from Shape in Android?

Path is a programmatic class for building arbitrary contours in code. Shape (GradientDrawable) is an XML resource for describing simple geometric forms. Path gives full control over geometry, while Shape is a quick way to define standard shapes. Path is suitable for custom drawing, Shape — for backgrounds and simple elements.

Summary

  • Path is a vector contour for describing arbitrary geometric shapes in Android.
  • moveTo sets the starting point, lineTo draws lines, quadTo and cubicTo draw Bezier curves.
  • addCircle, addRect, addOval, and addRoundRect add ready-made geometric shapes.
  • close closes the contour by connecting the last and first points.
  • Path.Op provides boolean operations: UNION, INTERSECT, DIFFERENCE, XOR.
  • Create Path once and reuse it to save CPU resources.
  • Use PathMeasure for animation along the contour and path length estimation.

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also