Contents

balochcodes/interactiveticket

A realistic, perforated event ticket and flight boarding pass card for SwiftUI featuring authentic vector circular notch cutouts, dashed tear lines, two-compartment architecture, and interactive 3D perspective tilt physics.

✨ Features

  • βœ‚οΈ Authentic Vector Cutout Notches: Smooth inward semicircular arc cutouts on both left and right ticket edges using native vector path geometry.
  • ➿ Dashed Perforation Tear Line: Realistic dashed divider line spanning between the side notches.
  • πŸ•ΉοΈ Interactive 3D Perspective Tilt: Smooth touch drag gestures tilt the ticket card in 3D perspective space with natural spring-back dampening upon release.
  • πŸŒ“ Two-Compartment Architecture: Separates primary upper content (body) from the validation stub/barcode area (stub).
  • 🎨 Rich Styling: Solid backgrounds, multi-stop gradients, customizable shadows, corner radiuses, and notch sizes.
  • ⚑ Zero External Dependencies: Built 100% on native SwiftUI primitives.

πŸ“¦ Installation

In Xcode (Recommended)

  1. Open your project in Xcode and go to File βž” Add Package Dependencies...
  2. In the search box, paste:

``text https://github.com/BalochCodes/InteractiveTicket.git ``

  1. Select Up to Next Major Version (1.0.0) and click Add Package.

In Package.swift

Add InteractiveTicket to your dependencies:

dependencies: [
    .package(url: "https://github.com/BalochCodes/InteractiveTicket.git", from: "1.0.0")
]

Import the framework:

import SwiftUI
import InteractiveTicket

πŸš€ Usage Examples

1. Airline Flight Boarding Pass

import SwiftUI
import InteractiveTicket

struct BoardingPassView: View {
    var body: some View {
        InteractiveTicketView(
            width: 320,
            height: 460,
            splitFraction: 0.72,
            notchRadius: 14,
            cornerRadius: 20,
            backgroundColor: .white,
            body: {
                VStack(alignment: .leading, spacing: 18) {
                    HStack {
                        Text("FLIGHT EK-204")
                            .font(.caption.bold())
                            .foregroundColor(.blue)
                        Spacer()
                        Text("GATE B12")
                            .font(.caption.bold())
                    }

                    HStack {
                        VStack(alignment: .leading) {
                            Text("DXB")
                                .font(.system(size: 34, weight: .heavy, design: .rounded))
                            Text("Dubai, UAE")
                                .font(.caption)
                                .foregroundColor(.secondary)
                        }

                        Spacer()
                        Image(systemName: "airplane")
                            .font(.title2)
                            .foregroundColor(.blue)
                        Spacer()

                        VStack(alignment: .trailing) {
                            Text("LHR")
                                .font(.system(size: 34, weight: .heavy, design: .rounded))
                            Text("London, UK")
                                .font(.caption)
                                .foregroundColor(.secondary)
                        }
                    }

                    Divider()

                    HStack {
                        VStack(alignment: .leading, spacing: 2) {
                            Text("PASSENGER")
                                .font(.system(size: 9, weight: .bold))
                                .foregroundColor(.secondary)
                            Text("Shahzain B.")
                                .font(.subheadline.bold())
                        }
                        Spacer()
                        VStack(alignment: .trailing, spacing: 2) {
                            Text("SEAT")
                                .font(.system(size: 9, weight: .bold))
                                .foregroundColor(.secondary)
                            Text("14A (Window)")
                                .font(.subheadline.bold())
                        }
                    }
                }
                .padding(22)
            },
            stub: {
                VStack(spacing: 6) {
                    Image(systemName: "qrcode")
                        .font(.system(size: 48))
                    Text("SCAN AT BOARDING GATE")
                        .font(.system(size: 10, weight: .bold, design: .rounded))
                        .foregroundColor(.secondary)
                }
                .padding(.vertical, 12)
            }
        )
    }
}

2. VIP Music Festival Ticket with Gradient

InteractiveTicketView(
    width: 320,
    height: 420,
    splitFraction: 0.68,
    gradient: LinearGradient(
        colors: [Color(red: 0.12, green: 0.11, blue: 0.29), Color(red: 0.19, green: 0.18, blue: 0.51)],
        startPoint: .topLeading,
        endPoint: .bottomTrailing
    ),
    perforationColor: Color(red: 0.39, green: 0.40, blue: 0.95),
    body: {
        VStack(alignment: .leading, spacing: 10) {
            Text("VIP ACCESS PASS")
                .font(.caption.bold())
                .foregroundColor(Color(red: 0.65, green: 0.71, blue: 0.99))

            Text("Electric Horizon 2026")
                .font(.title2.bold())
                .foregroundColor(.white)

            Text("SECTION: FRONT STAGE β€’ ROW: A β€’ SEAT: 01")
                .font(.footnote)
                .foregroundColor(.white.opacity(0.75))
        }
        .padding(24)
    },
    stub: {
        Text("#EH-2026-9812-VIP")
            .font(.system(size: 13, weight: .bold, design: .monospaced))
            .foregroundColor(.white.opacity(0.85))
    }
)

3. Flat Discount Promo Coupon Voucher

InteractiveTicketView(
    width: 300,
    height: 200,
    splitFraction: 0.70,
    enableTilt: false, // Disables touch 3D tilt
    backgroundColor: Color(red: 0.99, green: 0.95, blue: 0.78),
    perforationColor: Color(red: 0.96, green: 0.62, blue: 0.04),
    body: {
        VStack(spacing: 4) {
            Text("SPECIAL OFFER")
                .font(.caption.bold())
                .foregroundColor(.orange)
            Text("GET 30% OFF")
                .font(.title.bold())
                .foregroundColor(Color(red: 0.57, green: 0.25, blue: 0.05))
        }
    },
    stub: {
        Text("CODE: SAVE30")
            .font(.subheadline.bold())
            .foregroundColor(Color(red: 0.71, green: 0.33, blue: 0.04))
    }
)

πŸ› οΈ API Reference

InteractiveTicketView

| Parameter | Type | Default | Description | | :--- | :--- | :--- | :--- | | body | () -> BodyContent | Required | The upper primary content compartment of the ticket. | | stub | () -> StubContent | Required | The lower tear-off coupon / barcode compartment. | | height | CGFloat | 460.0 | Total height of the ticket card view. | | width | CGFloat? | 320.0 | Fixed width (or container width if nil). | | splitFraction | CGFloat | 0.70 | Fractional position (0.0 - 1.0) where the tear line sits. | | notchRadius | CGFloat | 14.0 | Radius of the circular side cutouts. | | cornerRadius | CGFloat | 18.0 | Outer border radius for all four corners. | | backgroundColor| Color | .white | Ticket surface fill color. | | gradient | LinearGradient?| nil | Optional gradient fill overriding background color. | | shadowColor | Color | black.opacity(0.18) | Dropshadow color beneath the ticket shape. | | shadowRadius | CGFloat | 16.0 | Blur radius of the elevation dropshadow. | | enableTilt | Bool | true | Enables interactive 3D perspective tilt on touch drag. | | perforationColor | Color | primary.opacity(0.18)| Color of the dashed tear line dividing body and stub. |


πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

Author

Created by Shahzain Baloch.

Package Metadata

Repository: balochcodes/interactiveticket

Default branch: main

README: README.md