tvOS Platform Patterns
Siri Remote Input
tvOS uses the Siri Remote — all interaction is through focus and button presses:
// Handle directional movement
.onMoveCommand { direction in
switch direction {
case .up: moveUp()
case .down: moveDown()
case .left: moveLeft()
case .right: moveRight()
@unknown default: break
}
}
// Handle Play/Pause button
.onPlayPauseCommand {
togglePlayback()
}
// Handle Menu/Back button
.onExitCommand {
dismiss()
}
// Long press on select button
.onLongPressGesture {
showOptions()
}
Media Playback (AVKit)
import AVKit
struct PlayerView: View {
let url: URL
@State private var player: AVPlayer?
var body: some View {
VideoPlayer(player: player)
.onAppear {
player = AVPlayer(url: url)
player?.play()
}
.onDisappear {
player?.pause()
}
.ignoresSafeArea()
}
}
Top Shelf Extension
The only supported extension type on tvOS — shows content on the home screen:
// In Targets/TopShelf/ContentProvider.swift
import TVServices
struct TopShelfProvider: TVTopShelfProvider {
var topShelfStyle: TVTopShelfContentStyle { .sectioned }
var topShelfItems: [TVTopShelfSectionedItem] {
let section = TVTopShelfItemCollection(items: [
makeItem(id: "1", title: "Featured Movie", imageURL: url1),
makeItem(id: "2", title: "New Release", imageURL: url2),
])
section.title = "Featured"
return [section]
}
func makeItem(id: String, title: String, imageURL: URL) -> TVTopShelfSectionedItem {
let item = TVTopShelfSectionedItem(identifier: id)
item.title = title
item.setImageURL(imageURL, for: .screenScale1x)
item.displayAction = TVTopShelfAction(url: URL(string: "myapp://item/\(id)")!)
return item
}
}
Parallax Effect (Focus Art)
tvOS automatically applies parallax effects to images in focused buttons:
// Images inside .buttonStyle(.card) get parallax automatically
Button { } label: {
Image("poster")
.resizable()
.aspectRatio(2/3, contentMode: .fill)
.frame(width: 200, height: 300)
}
.buttonStyle(.card)
Search
struct SearchView: View {
@State private var query = ""
@State private var results: [Item] = []
var body: some View {
NavigationStack {
VStack {
// tvOS shows system keyboard for text input
TextField("Search", text: $query)
.onChange(of: query) { _, newQuery in
search(newQuery)
}
if results.isEmpty {
ContentUnavailableView.search(text: query)
} else {
ScrollView {
LazyVGrid(columns: [
GridItem(.adaptive(minimum: 200), spacing: 40)
], spacing: 40) {
ForEach(results) { item in
NavigationLink(value: item) {
ItemCard(item: item)
}
.buttonStyle(.card)
}
}
.padding(.horizontal, 80)
}
}
}
.navigationTitle("Search")
}
}
}
Settings Pattern
NavigationStack {
List {
Section("Account") {
NavigationLink("Profile") { ProfileView() }
NavigationLink("Subscriptions") { SubscriptionView() }
}
Section("Playback") {
Toggle("Auto-Play Next", isOn: $autoPlay)
Picker("Quality", selection: $quality) {
Text("Auto").tag(Quality.auto)
Text("High").tag(Quality.high)
Text("Low").tag(Quality.low)
}
}
Section("About") {
LabeledContent("Version", value: "1.0")
}
}
.navigationTitle("Settings")
}
NOT Available on tvOS
- No camera, microphone, or photo library access
- No HealthKit, Core Motion, or biometrics (Face ID/Touch ID)
- No Maps or MapKit
- No haptic feedback
- No WebKit or Safari
- No user-facing push notifications (only silent push for content updates)
- No NFC, Bluetooth LE scanning, or ARKit
- No share sheet or social sharing
- No App Clips
- No home screen widgets
Rules
- ALL user interaction is through the Siri Remote — never assume touch input
- Handle
onMoveCommand,onPlayPauseCommand,onExitCommandfor remote control - Focus management is critical — test every screen's focus flow
- Use
AVKitfor video playback — tvOS has deep system integration - Top Shelf is the ONLY extension type — use TVServices framework
- Design for 10-foot viewing distance — large text, high contrast, simple layouts
- Prefer selection-based input (pickers, toggles) over text fields
- Keep session state — TV apps are often backgrounded during use
微信扫一扫