Published OnApril 1, 2025November 22, 2023

Building an airline seat map in SwiftUI

I've been asked to do a tutorial about building an airline seat map in SwiftUI many times. This has been my go-to snippet for years! It's super customizable and provides an awesome starter for any iOS developer in aviation.

If you've ever booked a flight, you're familiar with the seat map where you choose your preferred seat. In this tutorial, we'll replicate this feature using SwiftUI.

Step 1: Define the Data Model

Let's start by defining our data model:

enum SeatState {
    case empty
    case occupied
}

struct SeatId: Equatable, Hashable {
    var row: Int
    var letter: String
}

struct Seat: Identifiable, Equatable {
    var id: SeatId
    var state: SeatState
}

Here, each Seat has an id (consisting of its row and letter) and a state (which can be either empty or occupied).

Step 2: Create the Seat View

We need a visual representation of our seat:

struct SeatView: View {
    var seat: Seat

    var body: some View {
        Text(seat.id.letter)
            .frame(width: 40, height: 40)
            .background(seat.state == .empty ? Color.green : Color.red)
            .cornerRadius(8)
            .overlay(
                RoundedRectangle(cornerRadius: 8)
                    .stroke(Color.black, lineWidth: 2)
            )
    }
}

The SeatView displays the seat letter and changes its background based on its state.

Step 3: Build the Seat Map

Our goal is a grid layout with 2 seats, an aisle with a row number, 3 seats, another aisle, and then 2 more seats:

struct FirstClassView: View {

    @State var seats: [Seat] = (1..<25).map { row in
        ["A", "B", "C", "D", "E", "F", "G"].map { letter in
            Seat(id: SeatId(row: row, letter: letter), state: .empty)
        }
    }.flatMap { $0 }

    var columns: [GridItem] = [
        .init(.flexible()),  // A seat
        .init(.flexible()),  // B seat
        .init(.fixed(40)),   // Aisle with row number
        .init(.flexible()),  // C seat
        .init(.flexible()),  // D seat
        .init(.flexible()),  // E seat
        .init(.fixed(40)),   // Aisle with row number
        .init(.flexible()),  // F seat
        .init(.flexible())   // G seat
    ]

    var body: some View {
        ScrollView([.vertical, .horizontal], showsIndicators: true) {
            LazyVGrid(columns: columns, spacing: 20) {
                ForEach(seats) { seat in
                    switch seat.id.letter {
                    case "A", "B", "C", "D", "E", "F", "G":
                        SeatView(seat: seat)
                            .onTapGesture {
                                toggleSeat(seat: seat)
                            }
                    default:
                        Spacer()
                    }

                    if seat.id.letter == "B" || seat.id.letter == "E" {
                        Text("\(seat.id.row)")
                            .font(.headline)
                            .frame(width: 40, height: 40)
                    }
                }
            }
            .padding()
        }
    }

    func toggleSeat(seat: Seat) {
        if let index = seats.firstIndex(of: seat) {
            seats[index].state = seats[index].state == .empty ? .occupied : .empty
        }
    }
}

With SwiftUI, building complex layouts becomes a breeze. Our seat map, with different configurations and aisles, is just a demonstration of how adaptable and flexible SwiftUI grids can be.

Remember, you can further customize the appearance, add more features like zooming, selecting multiple seats, or fetching seat availability from a server. The possibilities are limitless! Happy coding!

Read more
Product
Tutorial
April 24, 2025
Engineering with Expo: Expanding Our JavaScript SDK
by
Teodor Ciuraru
In this article, we’ll detail how we introduced Expo Development Builds support for Ditto React Native and how the new Expo plugin helps developers skip several manual setup steps that React Native CLI users typically face.
Updates
Product
April 22, 2025
Flutter for Web Reaches General Availability in Record Time
by
Rae McKelvey
As of Ditto Flutter SDK v4.10.1, Flutter for Web has reached General Availability. In October 2024, when we shipped 4.8, Ditto developers started asking if we could extend Ditto to support Flutter web apps – and we took that challenge to heart. With the GA, let's take a closer look at what's included today, some key considerations, and how you can get started today.