Ora

How do I rotate text in SwiftUI?

Published in SwiftUI Text Rotation 4 mins read

To rotate text in SwiftUI, you primarily use the rotationEffect(_:anchor:) modifier. This powerful modifier allows you to specify an Angle by which the text should be rotated, and optionally, an anchor point around which the rotation occurs.

How to Rotate Text in SwiftUI

Rotating text in SwiftUI is straightforward using the rotationEffect view modifier. This modifier applies a 2D rotation to any View, including Text, around a specified anchor point.

Understanding rotationEffect

The rotationEffect modifier takes an Angle as its primary argument. This Angle can be a fixed value or, more dynamically, a variable that can change based on user interaction or application state.

Text("Hello, SwiftUI!")
    .rotationEffect(.degrees(45)) // Rotates the text by 45 degrees

The Angle type in SwiftUI offers convenient ways to specify rotation:

Angle Type Description Example
.degrees() Specifies the angle in degrees (0-360). .degrees(90)
.radians() Specifies the angle in radians (0-2π). .radians(.pi / 2)

Static Text Rotation

For a fixed rotation, you simply provide a specific Angle value.

import SwiftUI

struct StaticRotationExample: View {
    var body: some View {
        VStack(spacing: 40) {
            Text("Rotated 30 Degrees")
                .font(.title)
                .padding()
                .background(Color.blue.opacity(0.2))
                .rotationEffect(.degrees(30))

            Text("Rotated -45 Degrees")
                .font(.title2)
                .padding()
                .background(Color.green.opacity(0.2))
                .rotationEffect(.degrees(-45))

            Text("Rotated 90 Degrees")
                .font(.headline)
                .padding()
                .background(Color.purple.opacity(0.2))
                .rotationEffect(.degrees(90))
        }
    }
}

struct StaticRotationExample_Previews: PreviewProvider {
    static var previews: some View {
        StaticRotationExample()
    }
}

Dynamic Text Rotation with a Variable

To achieve interactive or animated rotations, you'll make the Angle a variable that changes its value. This is a powerful technique for creating dynamic user interfaces. You can use @State variables to manage the angle, which can then be updated by a Slider, a Stepper, or even a RotationGesture.

Here’s an example using a Slider to dynamically control the text's rotation:

import SwiftUI

struct DynamicRotationExample: View {
    @State private var rotationAngle: Angle = .zero // Our variable angle

    var body: some View {
        VStack(spacing: 30) {
            Text("Drag to Rotate Me!")
                .font(.largeTitle)
                .fontWeight(.bold)
                .foregroundColor(.white)
                .padding(20)
                .background(Color.red)
                .cornerRadius(15)
                .rotationEffect(rotationAngle) // Applying the variable angle
                .animation(.spring(), value: rotationAngle) // Smooth animation

            Slider(value: $rotationAngle.degrees, in: -180...180) {
                Text("Rotation")
            } minimumValueLabel: {
                Text("-180°")
            } maximumValueLabel: {
                Text("180°")
            }
            .padding(.horizontal)

            Text("Current Angle: \(rotationAngle.degrees, specifier: "%.1f")°")
                .font(.callout)
        }
        .padding()
    }
}

struct DynamicRotationExample_Previews: PreviewProvider {
    static var previews: some View {
        DynamicRotationExample()
    }
}

In this example:

  • @State private var rotationAngle: Angle = .zero declares a state variable to hold the current rotation angle.
  • rotationEffect(rotationAngle) applies this variable angle to the Text view.
  • The Slider is bound to $rotationAngle.degrees, allowing the user to change the angle interactively.
  • .animation(.spring(), value: rotationAngle) provides a smooth animation whenever rotationAngle changes.

Customizing the Anchor Point

By default, rotationEffect rotates a view around its center. You can specify a different anchor point using the anchor: parameter. Common anchor points include:

  • .center (default)
  • .top, .bottom, .leading, .trailing
  • .topLeading, .topTrailing, .bottomLeading, .bottomTrailing

For instance, to rotate text around its bottom-leading corner:

Text("Pivot Here")
    .font(.title)
    .padding()
    .background(Color.orange.opacity(0.3))
    .rotationEffect(.degrees(45), anchor: .bottomLeading)
    .border(Color.orange) // Visual aid for the view's original bounds

Rotation Gestures

For a more interactive experience, you can combine rotationEffect with RotationGesture. This allows users to rotate the text directly with their fingers on a touch screen.

import SwiftUI

struct GestureRotationExample: View {
    @State private var currentRotation: Angle = .zero
    @State private var accumulatedRotation: Angle = .zero

    var body: some View {
        Text("Rotate Me with Two Fingers!")
            .font(.title)
            .padding(30)
            .background(Color.cyan.opacity(0.5))
            .cornerRadius(20)
            .rotationEffect(currentRotation + accumulatedRotation) // Apply combined rotation
            .gesture(
                RotationGesture()
                    .onChanged { angle in
                        currentRotation = angle // Update current rotation during gesture
                    }
                    .onEnded { angle in
                        accumulatedRotation = accumulatedRotation + currentRotation // Lock in rotation
                        currentRotation = .zero // Reset current for next gesture
                    }
            )
            .padding()
    }
}

struct GestureRotationExample_Previews: PreviewProvider {
    static var previews: some View {
        GestureRotationExample()
    }
}

In this example:

  • currentRotation stores the rotation during the active gesture.
  • accumulatedRotation stores the total rotation from previous gestures.
  • The RotationGesture's onChanged closure updates currentRotation as the user rotates, and onEnded adds currentRotation to accumulatedRotation for persistent rotation.

By utilizing rotationEffect with Angle variables and combining it with UI controls or gestures, you can achieve sophisticated and interactive text rotations in your SwiftUI applications.