Skip to content

SwiftUI and UIKit native picker

Customize the iOS 0.3.4 picker or build a complete SwiftUI/UIKit layout from the public controller, map, and native components.

Updated View as Markdown

iOS 0.3.4 provides one native picker implementation for SwiftUI and UIKit. The ready-made flow, customization layers, public component catalogue, scoped composition, lifecycle recovery, and typed checkout handoff are part of the tagged Swift package.

Application and SDK ownership

Native SwiftUI/UIKit owns SeatLayer SDK owns
Event header, filters, floor/section navigation, confirmation, tiers and quantities, cart, hold state, checkout, loading/errors, Test Mode, attribution and Back Seats, labels, venue geometry, hit testing, pan/pinch, camera, authored 3D, and panorama pixels
Dynamic Type, VoiceOver, safe areas, scene lifecycle, native presentation and haptics Authoritative inventory state and supported map capabilities

The picker exposes a replaceable native buyer component tree while SeatLayer keeps venue geometry and inventory behavior behind the public SDK API.

Integration ladder

Path API Host ownership
Ready SwiftUI SeatLayerPicker Configuration and callbacks
Ready UIKit SeatLayerPickerViewController Navigation and dismissal
Branded picker Theme, strings, options, styles, builders Brand or selected complete parts
Custom SwiftUI SeatLayerPickerScope + public views Entire SwiftUI hierarchy
Custom UIKit SeatLayerPickerMapView or SeatLayerPickerMapViewController + controller Entire UIKit hierarchy
Raw map SeatLayerView Every buyer surface and transition

Ready-picker contract

SeatLayerPicker(
    configuration: SeatLayerConfiguration(
        event: "ev_your_event_key",
        publicKey: "pk_test_your_public_key",
        locale: "en",
        currency: "USD"
    ),
    onCheckout: { handoff in
        try await checkoutBackend.begin(holdId: handoff.holdId)
    }
)

For private inventory, replace publicKey with a renewable buyerAccessTokenProvider backed by your server. Return only the short-lived native buyer-access token and treat the SDK access context as opaque.

UIKit’s SeatLayerPickerViewController hosts the same public component tree. Call handleBack() from host navigation and use updateAppearance(theme:themeMode:strings:styles:) for in-place appearance changes.

Four customization layers

Theme native and map roles together

let theme = SeatLayerPickerTheme(
    background: "#0F1522",
    surface: "#1A2234",
    text: "#EEF1F8",
    accent: "#FF6584",
    onAccent: "#111827",
    map: SeatLayerPickerMapTheme(
        background: "#0F1522",
        rowLabelColor: "#D7DEEA",
        textColor: "#EEF1F8",
        selectionColor: "#FF6584"
    )
)

.auto follows the current color scheme without rebuilding the picker.

Style one surface

var styles = SeatLayerPickerStyles()
styles[.checkoutBar] = SeatLayerPickerPartStyle(
    background: "#FF6584",
    cornerRadius: 18,
    horizontalPadding: 12,
    verticalPadding: 8
)

A style changes appearance, not placement, inventory truth, or hit targets.

Change optional chrome and wording

let options = SeatLayerPickerOptions(
    chrome: SeatLayerPickerChromeOptions(floorStrip: false)
)

let strings = SeatLayerPickerStrings(
    overrides: [
        SeatLayerPickerStringKey.continueWord.rawValue: "Review order"
    ],
    localeIdentifier: "fr-FR"
)

The 37 bundled locale dictionaries resolve exact BCP-47 tag, then language, then English. Event and inventory data supplied by SeatLayer stays authoritative.

Wrap or replace one complete part

var builders = SeatLayerPickerBuilders()
builders.header = { context in
    AnyView(
        context.defaultContent
            .background(.ultraThinMaterial)
    )
}

Every builder receives the current read-only state, controller, presentation state, resolved style, and canonical defaultContent. Missing or throwing builders fall back to the stock component. Test Mode and attribution deliberately have no builder authority.

Build your own SwiftUI hierarchy

SeatLayerPickerScope gives the tree one controller, one presentation model, and one picker state.

let options = SeatLayerPickerOptions(confirmSelection: true)

SeatLayerPickerScope(options: options) { controller in
    ZStack {
        SeatLayerPickerMap(
            configuration: SeatLayerConfiguration(
                event: "ev_your_event_key",
                publicKey: "pk_test_your_public_key"
            ),
            options: options,
            controller: controller
        )

        VStack {
            SeatLayerPickerHeader()
            SeatLayerPickerPriceLegend()
            SeatLayerPickerFloorStrip()
            Spacer()
            SeatLayerPickerDockBar()
            SeatLayerPickerCartList()
        }
    }
}

Callbacks observe rather than own the flow. Custom UI invokes typed semantic controller actions such as focusSection, overview, setFloor, setCategoryFilter, refreshAvailability, and checkout.

UIKit applications that own all chrome use SeatLayerPickerMapView or SeatLayerPickerMapViewController, observe pickerController.snapshot, and call the same public controller actions.

Public component catalogue

The ready picker is composed from these same public surfaces:

Buyer job Default components
Identity and venue navigation SeatLayerPickerHeader, price legend, floor selector/strip, section navigator, dock bar
Map and filters SeatLayerPickerMap, map controls, accessibility filters
Decisions Best-seats form, seat confirmation/confirm card, tier choices, GA and table prompts
Cart and hold Cart list/sheet, checkout bar, hold countdown, hold-lapse notice, action error
Immersive SeatLayerVenue3D, SeatLayerSeatViewChrome
System states Loading, retryable/fatal error, empty/sold-out/sales-closed
Truth components SeatLayerPickerTestModeIndicator, SeatLayerPickerAttribution

There are 25 replaceable builder parts. Test Mode and attribution are public truth components outside that replacement matrix.

State and checkout guarantees

  • Picker state always belongs to the active Event and supersedes older state.
  • Inventory-changing actions are serialized.
  • Repeated Continue taps join one checkout flight.
  • Pending tier choice is applied before confirmation and remains authoritative through cart and handoff.
  • Ordinary picker state omits holdId; only SeatLayerPickerCheckoutHandoff exposes it.
  • A successful callback transfers hold ownership to the host.
  • A rejected callback rejects only that handoff and returns ownership safely.
  • initialHoldId restores a host-owned hold; readOnly: true blocks mutation through both ready-made and custom controller paths.

Lifecycle and recovery

The ready SwiftUI picker observes scenePhase; UIKit observes application notifications. Foreground reconciliation consumes hold lapse, unavailable inventory, and authoritative server hold state before new actions. Custom hosts use lifecycle, refreshAvailability(), and synchronize().

Back closes the most local state first: prompt → cart → confirmation → focused section → venue → host. Immersive 3D and panorama actions are capability-gated, so unsupported actions are never presented or sent.

Test Mode and required attribution

Custom hosts must render truthful Test Mode state and the bottom-right attribution when required by the SeatLayer account configuration. Chrome options and builders cannot force or suppress it.

Production checklist

  • Pin exact Swift package 0.3.4.
  • Validate SwiftUI and UIKit paths used by your product.
  • Exercise Dynamic Type, VoiceOver, RTL, rotation, foreground/background, interactive dismissal, hold lapse, unavailable inventory, and rejected checkout.
  • Test real tiers, 3D targets, panorama navigation, Test Mode, and attribution.
  • Verify supported physical devices; simulator success is not device proof.
  • Confirm the trusted backend inspects and books the handoff hold.

Product scope

The picker selects one Event. It does not accept native Performance Group or Season configuration.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close