Swift and SwiftUI tutorials for Swift Developers

How to Draw a Line in SwiftUI

If you are taking your first steps or looking to hone your skills in Swift programming, you have come to the right place. Every iOS Developer eventually faces the need to create custom user interfaces. Sometimes, the seemingly simplest tasks, like drawing a line in SwiftUI, hide different approaches and techniques worth mastering.

In this  tutorial we will explore all the possible ways to draw lines using SwiftUI, Apple’s declarative framework. Best of all, the Swift code we write in Xcode will be cross-platform, meaning it will work flawlessly on iOS, macOS, and watchOS.


1. The Workspace: Setting up Xcode

Before we start writing lines of code (literally and figuratively), we need to set up our environment.

  1. Open Xcode.
  2. Select Create a new Xcode project.
  3. Choose the Multiplatform tab and select App. This ensures our code is ready for iOS, macOS, and watchOS.
  4. Name your project (e.g., SwiftUILinesTutorial), make sure the selected interface is SwiftUI and the language is Swift.

As an iOS Developer, mastering the SwiftUI canvas in Xcode will drastically speed up your workflow. Let’s get started!


2. The Fundamental Method: Using Path

The most direct and raw way to draw a line in SwiftUI is by using the Path structure. A Path is basically a set of 2D drawing instructions (like a vector path).

In the SwiftUI coordinate system, the origin point (0, 0) is located at the top-left corner of the view.

Here is how to draw a simple diagonal line:

import SwiftUI

struct PathLineView: View {
    var body: some View {
        Path { path in
            // 1. We move the "pencil" to the starting point
            path.move(to: CGPoint(x: 50, y: 50))
            
            // 2. We draw the line to the destination point
            path.addLine(to: CGPoint(x: 250, y: 250))
        }
        // 3. We define how the line will look (color and thickness)
        .stroke(Color.blue, lineWidth: 5)
        .frame(width: 300, height: 300)
    }
}

Explanation for the iOS Developer:

  • move(to:): Lifts the virtual pencil and places it at specific coordinates without drawing anything.
  • addLine(to:): Drags the pencil from the current position to the new coordinates.
  • .stroke(): Without this modifier, the Path is invisible. We give it a blue color and a thickness of 5 points.

This code is 100% compatible with iOS, macOS, and watchOS.


3. The Reusable Way: Creating a Custom Shape

Using Path directly in the view is fine for quick things, but in SwiftUI-oriented Swift programming, the best practice is to create reusable components. To do this, we can conform our own structure to the Shape protocol.

When creating a Shape, SwiftUI provides us with a rectangle (CGRect) representing the available space, allowing us to draw lines relative to the view’s size.

import SwiftUI

struct Line: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        
        // We draw a horizontal line from end to end
        path.move(to: CGPoint(x: 0, y: rect.midY))
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
        
        return path
    }
}

// Usage in our main view
struct ShapeLineView: View {
    var body: some View {
        VStack(spacing: 40) {
            Line()
                .stroke(Color.red, lineWidth: 3)
                .frame(height: 100)
            
            Line()
                .stroke(Color.green, style: StrokeStyle(lineWidth: 5, dash: [10, 5]))
                .frame(height: 100)
        }
        .padding()
    }
}

The advantages of this approach:

As an iOS Developer, you will notice that by using Shape, the line automatically adapts to its container. If you compile this in Xcode for an Apple Watch (watchOS) or a Mac (macOS), the horizontal line will intelligently use the available width.


4. Styling Your Lines (StrokeStyle)

Drawing a line in SwiftUI doesn’t end with a simple solid stroke. SwiftUI offers StrokeStyle to completely customize our lines.

You can modify parameters such as:

  • lineWidth: The thickness of the line.
  • lineCap: The shape of the line’s ends (.round, .butt, .square).
  • lineJoin: How two lines of the same path connect.
  • dash: An array defining a dashed line pattern.

Let’s see an advanced customization example in Swift:

import SwiftUI

struct StyledLineView: View {
    var body: some View {
        Path { path in
            path.move(to: CGPoint(x: 20, y: 100))
            path.addLine(to: CGPoint(x: 300, y: 100))
        }
        .stroke(
            Color.purple,
            style: StrokeStyle(
                lineWidth: 10,
                lineCap: .round,
                dash: [20, 10] // 20 pt line, 10 pt space
            )
        )
        .frame(height: 200)
    }
}

5. Practical Alternatives: Divider and Rectangle

Sometimes, you don’t need to use a Path or a Shape. If your goal as an iOS Developer is simply to separate content visually, modern Swift programming gives us semantic shortcuts.

Using Divider

A Divider is the native SwiftUI element for creating separation lines. It is subtle, automatically adapts to the OS light/dark mode, and requires zero effort.

import SwiftUI

struct DividerView: View {
    var body: some View {
        VStack {
            Text("Top")
            
            Divider() // The automatic separation line
                .background(Color.red) // You can tint it if you want
            
            Text("Bottom")
        }
        .padding()
    }
}

The Rectangle Trick

Another common technique in Swift programming for UI is using a rectangle with a height or width of 1 or 2 points. This is useful when you want absolute control over the color and background without using Path.

import SwiftUI

struct RectangleLineView: View {
    var body: some View {
        Rectangle()
            .fill(Color.orange)
            .frame(height: 2) // This visually turns it into a line
            .edgesIgnoringSafeArea(.horizontal)
    }
}

6. Taking Your Code to the Next Level: Animating Lines

No SwiftUI tutorial for a true iOS Developer would be complete without a bit of magic. Thanks to how SwiftUI works, animating the drawing of a line is incredibly simple using the .trim modifier.

The .trim(from:to:) modifier allows drawing only a percentage of the Path or Shape. If we animate the to value, we can create a “drawing in progress” effect.

Try it out in your Xcode simulator:

import SwiftUI

struct AnimatedLineView: View {
    // State to control the animation
    @State private var endAmount: CGFloat = 0.0

    var body: some View {
        VStack {
            Line()
                .trim(from: 0.0, to: endAmount) // Controls how much is drawn
                .stroke(Color.blue, lineWidth: 5)
                .frame(width: 250, height: 50)
                .onAppear {
                    // We trigger the animation when the view appears
                    withAnimation(.easeInOut(duration: 2.0).repeatForever(autoreverses: false)) {
                        endAmount = 1.0
                    }
                }
        }
    }
}

These kinds of details are what elevate an average app to a premium user experience, and with SwiftUI in Xcode, it takes very few lines of Swift code.


7. Cross-Platform Considerations (iOS, macOS, watchOS)

One of the biggest promises of SwiftUI is its portability. When you decide to draw a line in SwiftUI, structures like Path, Shape, and modifiers like .stroke work identically across Apple’s three main operating systems.

However, as a good iOS Developer, you must consider the context of the screen:

  • iOS / iPadOS: You have plenty of space. Lines with touch interaction (using DragGesture) are common.
  • macOS: The user interacts with a mouse. You can use a vertical Divider in a toolbar (Toolbar), which is a very Mac-like design pattern.
  • watchOS: Space is extremely limited. Use lines (Divider or very thin rectangles) with subtle colors or low opacity (.opacity(0.5)) to avoid cluttering the small OLED screen. Make sure to test your code in the Apple Watch simulators within Xcode.

Conclusion

We have covered a lot of ground in this tutorial. From understanding the coordinate system using Path, to creating reusable and scalable components with Shape, down to advanced animation and quick tricks using Rectangle or Divider.

Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Article

MagicReplace in SwiftUI

Next Article

fileImporter in SwiftUI

Related Posts