View in English

  • メニューを開く メニューを閉じる
  • Apple Developer
検索
検索を終了
  • Apple Developer
  • ニュース
  • 見つける
  • デザイン
  • 開発
  • 配信
  • サポート
  • アカウント
次の内容に検索結果を絞り込む

クイックリンク

5 クイックリンク

ビデオ

メニューを開く メニューを閉じる
  • コレクション
  • トピック
  • すべてのビデオ
  • 利用方法

WWDC20に戻る

ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。

  • 概要
  • トランスクリプト
  • コード
  • tvOS向けのSwiftUI Appを構築する

    SwiftUIでtvOS Appに新たな側面をもたらしましょう。ここでは、SwiftUIによってレイアウトを構築し、カスタムボタンでインターフェイスをカスタマイズし、コンテキストメニューでAppの機能性を高め、ビューのフォーカスを確認し、デフォルトのフォーカスを管理する方法をご紹介します。このセッションを有効活用するには、SwiftUIを使いこなせることが望まれます。まずは"Introducing SwiftUI: Building Your First App"と"SwiftUI On All Devices"をご覧ください。

    リソース

    • CardButtonStyle
    • Human Interface Guidelines: Designing for tvOS
    • isFocused
    • Learn to Make Apps with SwiftUI
    • prefersDefaultFocus(_:in:)
    • Supporting Multiple Users in Your tvOS App
    • SwiftUI
      • HDビデオ
      • SDビデオ

    関連ビデオ

    WWDC20

    • SwiftUIの新機能

    WWDC19

    • すべてのデバイスでのSwiftUI
    • SwiftUIの紹介:初めてのAppをビルドする
  • このビデオを検索

    こんにちは WWDCにようこそ “tvOS向けのSwiftUI Appを構築する” 私はタヌ・シンガル tvOSチームのエンジニアです Apple TV向けSwiftUI Appの 構築についてお話します 新規APIを紹介し ベストプラクティスを説明した後 TVユーザーにとって馴染みやすい体験を作り出す 一助となる事例を見ていきます

    最初にtvOS 14の新機能 ボタンスタイルと コンテクストメニューについて説明し

    次にApp上でフォーカスを 管理する方法をお話します

    最後に家庭の大画面で美しく見える レイアウトの作成方法を学びましょう TVには固有のボタンスタイルがあります 例をご覧ください Apple TVで音楽をストリーミングする Appを構築するとします これはデザインチームから受け取った モックアップです Siri Remoteでドラッグした時にボタンが動く 効果をつけてほしいという指定がありました この“アルバム”の下の ボタンのような感じです

    SwiftUIでこのようなボタンを作成するには 新しいCardButtonStyleが使えます

    CardButtonでフォーカスした時に浮き上がり 強調されたように見えるベースが作れます さらにSiri Remoteでドラッグした方向に動く 効果も加わります

    CardButtonの作成方法は ボタンにボタンスタイルモディファイアをつけ CardButtonStyleを設定するだけです

    CardButtonStyleがあれば ボタンのアピアランスが各段に向上します しかし 既存のボタンスタイルに 設定してあるような 強調やフォーカスの効果を 使いたくない場合もあるでしょう そのような時は独自に ボタンスタイルを作ることもできます この場合 プレスやフォーカスの状態に 既存の効果はついていません カスタムボタンスタイルを使えば 設定やカスタマイズがとても簡単です

    独自のボタンスタイルを作るにはまず ButtonStyleプロトコルに準拠させてください

    makeBodyメソッド内で設定を活用し あらゆるビューを呼び出せます

    設定したボタンスタイルはボタンスタイル モディファイアを使ったボタンに追加できます これでAppのボタンの設定ができましたが 他にも追加したい機能があります アルバムのボタンを長押しした時に この表示のような クイックアクションを起こしたいのです

    コンテクストメニューを使えば 簡単にSwiftUIに実装できます コンテクストメニューをボタンやビューに追加し 長押しの操作をした時に 呼び出すことができます コンテクストメニューに通常のボタンを使った アクションを足すこともできます

    これはコンテクストメニューの作り方を示す コードの例です コンテクストメニューモディファイアをつけ その中にボタンを追加するだけです ご覧のように新しいボタンスタイルと コンテクストメニューは非常に簡単に使えます きっとApp上で映えるでしょう 次にフォーカスについて説明します これはTV Appとやり取りをする際の要です ビューにフォーカスできるだけでなく ビューがフォーカスされているか 判断できることは非常に重要です 先ほどの音楽 Appを例に フォーカスについて詳しく見ていきましょう

    “再生中”の画面で 現在再生中の楽曲にフォーカスしましょう フォーカスしているこの楽曲の アーティスト名のほか アルバム名と音符の絵文字も 表示させたいと思います

    フォーカスしていない楽曲はアルバム名を除いて アーティスト名だけを表示します

    この動きを実装するには まずSongViewにフォーカスする必要があります フォーカス可能なモディファイアを使うのが 1つの方法です フォーカス可能なモディファイアで既存のビューの トップにフォーカス可能なラッパーを作ります

    このモディファイアは元来フォーカス可能な ビュー用ではないことに注意してください ですからUIKitでフォーカスを管理するボタンや リスト UIKitビューがある場合 そこではフォーカス可能なモディファイアを 使わない方がよいでしょう このモディファイアは既存のビューのトップに別の フォーカス可能なラッパーを追加するからです tvOS 13でフォーカス可能および フォーカス不可能な状態を管理する時は フォーカス可能なモディファイアにonFocusChange コールバック関数を使う必要がありました

    しかしtvOS 14では新たに isFocused環境変数を導入しています

    これによって特定のビューが フォーカスされているかチェックできます ビュー自体は フォーカス不可であっても構いません isFocused環境変数はビュー内の 直近のフォーカス可能な祖先が フォーカスされている場合にtrueを返します

    では前に示したSongViewのコードに戻りましょう これはテキストラベルがついた 画像が1点あります テキストラベルをDetailsViewに リファクタリングします

    DetailsView内で環境変数を使えば isFocusedはこのビューが フォーカスされているか否かをチェックします DetailsViewの親である SongViewがフォーカスされている場合 isFocused変数はtrueです

    このisFocused変数を使ってアーティスト名や アルバム名を絵文字と共に表示したり 表示がフォーカスされていない時 アーティスト名だけ表示したりするのも可能です SongViewではボタンを使うので フォーカス可能なモディファイアを使う必要は 一切ありません もともとボタンはフォーカス可能だからです ボタンを使うことで選択とアクセシビリティを 無料で活用できるのもメリットです

    既存のボタンスタイルについている既定の強調と フォーカスの効果を使いたくないので ここではオリジナルのボタンスタイルを 追加しました

    以上でAppの設定はほぼ完了し いつでも音楽の ストリーミングを開始できるようになりました

    ただユーザーがプレミアムコンテンツを聴けるよう このAppの有料版も追加したいです 有料版を作成するには 最初にサインイン画面を設定しましょう

    ユーザー名とパスワード欄に ログインボタンが並んだシンプルな画面です 初期設定でユーザー名欄が フォーカスされていることが分かります tvOSはローディング時にフォーカスすべき ビューを幾何学的に計算します 一般的には画面の最上段や 先頭のフォーカス可能なビューにあたります この場合 ユーザー名が フォーカスされているのは当然でしょう でも既にユーザー名やパスワードを知っていて 代わりにログインボタンに フォーカスしたい場合もあります

    この動作をSwiftUIに実装するには 新たな初期設定のフォーカスAPIを使います

    prefersDefaultFocusモディファイアを紹介しましょう 初期設定でフォーカスしたいビューを 指定することができます 小さなカスタムビューを設定している時に 全体のグローバルビューの階層を 誤って変更しないように注意してください この懸念を払しょくするために focusScopeモディファイアを用意しました これによってフォーカスの初期設定変更を 特定のビューに制限することができます 先ほど見たログイン画面のコードを 見てみましょう VStack TextField SecureFieldと ボタンがシンプルに並んでいます ここにフォーカスを管理するコードを追加します すぐに読解できなくても心配ありません 1行ずつ見ていきましょう 認証情報が入力されているかを確認する 状態変数があります ここでユーザー名のTextFieldに prefersDefaultFocusモディファイアを足します モディファイアの最初のパラメータはブーリアン関数で このビューをフォーカスの初期設定にした場合に trueを返します この場合 認証情報が未入力の時は 初期設定よりユーザー名を優先しフォーカスします 同じモディファイアをログインボタンにも追加します 認証情報が入力されている時は 初期設定のフォーカスを優先します 次にフォーカスの優先を設定中の VStackに制限してみましょう そのためにはネームスペースを作成します ネームスペースは動的プロパティで ビューの特定に用いる固有の IDが使えるようになります このネームスペースをVStackに追加した focusScopeモディファイアに足しましょう

    次に同じネームスペースを 2つ目のパラメータとして prefersDefaultFocusモディファイアに渡します これで初期設定の変更が VStackのみに適用されるようになりました ですからフォーカスをVStack内のみに設定すると 認証情報が入力されているか否か次第で それぞれユーザー名や ログインボタンがフォーカスされます しかしフォーカスがビュー階層の 別のどこかに当たるべき場合は 意向どおりモディファイアは グローバルのフォーカスには影響しません フォーカスの初期設定を指定する他に フォーカスをリセットしたい場合もあるでしょう それも新しいresetFocus環境アクションを使えば 対応可能です この環境アクションは フォーカスを初期設定にリセットします この場合もフォーカスの更新は 与えたネームスペースの範囲内にとどまります 先ほど見たサインイン画面の例で やり直しボタンも追加したいとしましょう ユーザー名とパスワードを消去し フォーカスをユーザー名に戻すボタンです 実装するには resetFocus環境アクションを使います やり直しボタンが発動したら focusScopeにあるのと同じネームスペースに resetFocusを呼び出します この時点で認証情報は消去されているので ユーザー名をフォーカスするようリセットされます このセクションではisFocus環境変数に加え フォーカスの初期設定を操作できる新規モディファイアや 環境アクションについて説明しました SwiftUI Appを構築する際に とても役立つと思います 最後にApple TVで一般的にみられる レイアウトの構築方法を知ってください これは先ほど見た 音楽ストリーミングAppのビューです さまざまなApple TV Appで 同様のレイアウトを見たことがあるでしょう これは水平にスクロールするシェルフで 構成されています この画面を実装する際は 新しいLazy Gridを使います

    これは垂直または水平にスクロールするグリッド コンテナ内に子ビューを配置するものです グリッドアイテムでサイズや配置 間隔など レイアウトの構築に役立つ プロパティを指定できます グリッドの詳細は次の2つの セッションをチェックしてください このセッションではLazy Gridを活用し 先ほどのようなレイアウトの構築法を学びます ShelfViewの中に水平にスクロールする ScrollViewを作成し 水平のScrollViewの中に LazyHGridを追加しました このLazyHGridには多数のアイテムを追加でき 一度にすべてが初期化されることはありません スクロール中 必要な時にローディングされます

    Lazy GridにGridItemも設定します GridItemサイズはフレキシブルに固定でき GridItem間のスペースもカスタマイズ可能です

    Lazy Gridの中にセル内で提示したい コンテンツを追加するだけです シェルフが整ったので 複数のシェルフをVStack内で積み重ねます テキストラベルもつけて 先ほど見たようなレイアウトを作ります Apple TVに美しいグリッドを表示させるのは こんなに簡単です 以上を要約しますと tvOS 14の新しいCardButtonStyleと コンテクストメニューをぜひお試しください とても簡単に使えてApp上できれいに映えます

    新たなフォーカスAPIを使うと App内のフォーカスを管理しやすくなり 非常に便利です

    最後にLazy Gridを活用すれば 短時間でtvOSのレイアウトを構築できます これから皆さんがSwiftUIで 構築するプロダクトを楽しみにしています それではWWDCが 素晴らしい体験になりますように

    • 1:42 - CardButtonStyle

      Button(albumLabel, action: playAlbum)
          .buttonStyle(CardButtonStyle())
    • 2:24 - Custom Button Styles

      struct MyNewButtonStyle: ButtonStyle {
          func makeBody(configuration: Configuration) -> some View {
              configuration.label
                 .background(configuration.isPressed ? … : …) // Custom styling
          }
      }           
      
      Button(albumLabel, action: playAlbum)
          .buttonStyle(MyNewButtonStyle())
    • 3:19 - Context Menus

      AlbumView()
          .contextMenu {
              Button("Add to Favorites", action: addAlbumToFavorites)
              Button("View Artist", action: viewArtistPage)
              Button("Discover Similar Albums", action: viewSimilarAlbums)
          }
    • 5:47 - isFocused Environment Variable

      struct SongView: View {
          var body: some View {
              Button(action: playSong) {
                  VStack {
                      Image(albumArt)
                      DetailsView(...)
                  }
              }.buttonStyle(MyCustomButtonStyle())
          }
      }
      
      struct DetailsView: View {
          ...
          @Environment(\.isFocused) var isFocused: Bool
          var body: some View {
              VStack {
                  Text(songName)
                  Text(isFocused ? artistAndAlbum : artistName)
              }
          }
      }
    • 8:42 - Login Screen (Default Focus)

      var body: some View {
          VStack {
              TextField("Username", text: $username)
      
              SecureField("Password", text: $password)
      
              Button("Log In", action: logIn)
      
          }
      
      }
    • 8:51 - Default Focus

      @Namespace private var namespace
      @State private var areCredentialsFilled: Bool
      
      var body: some View {
          VStack {
              TextField("Username", text: $username)
                  .prefersDefaultFocus(!areCredentialsFilled, in: namespace)            
              SecureField("Password", text: $password)
      
              Button("Log In", action: logIn)
                 .prefersDefaultFocus(areCredentialsFilled, in: namespace)
          }
          .focusScope(namespace)
      }
    • 11:12 - Reset Focus

      @Namespace private var namespace
      @State private var areCredentialsFilled: Bool
      @Environment(\.resetFocus) var resetFocus
      
      var body: some View {
          VStack {
              TextField("Username", text: $username)
                  .prefersDefaultFocus(!areCredentialsFilled, in: namespace)            
              SecureField("Password", text: $password)
      
              Button("Log In", action: logIn)
                 .prefersDefaultFocus(areCredentialsFilled, in: namespace)
      
              Button("Clear", action: { 
                  username = ""; password = ""
                  areCredentialsFilled = false
                  resetFocus(in: namespace)
              })
          }
          .focusScope(namespace)
      }
    • 12:45 - Lazy Grids

      struct ShelfView: View {
          var body: some View {
              ScrollView([.horizontal]) {
                  LazyHGrid(rows: [GridItem()]) {
                      ForEach(playlists, id: \.self) { playlist in                
                          Button(action: goToPlaylist) {
                              Image(playlist.coverImage)
                                  .resizable()
                                  .frame(…)
                          }
                          .buttonStyle(CardButtonStyle())
                      }
                  }
              }
          }
      }

Developer Footer

  • ビデオ
  • WWDC20
  • tvOS向けのSwiftUI Appを構築する
  • メニューを開く メニューを閉じる
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    メニューを開く メニューを閉じる
    • アクセシビリティ
    • アクセサリ
    • App Extension
    • App Store
    • オーディオとビデオ(英語)
    • 拡張現実
    • デザイン
    • 配信
    • 教育
    • フォント(英語)
    • ゲーム
    • ヘルスケアとフィットネス
    • アプリ内課金
    • ローカリゼーション
    • マップと位置情報
    • 機械学習
    • オープンソース(英語)
    • セキュリティ
    • SafariとWeb(英語)
    メニューを開く メニューを閉じる
    • 英語ドキュメント(完全版)
    • 日本語ドキュメント(一部トピック)
    • チュートリアル
    • ダウンロード(英語)
    • フォーラム(英語)
    • ビデオ
    Open Menu Close Menu
    • サポートドキュメント
    • お問い合わせ
    • バグ報告
    • システム状況(英語)
    メニューを開く メニューを閉じる
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles(英語)
    • フィードバックアシスタント
    メニューを開く メニューを閉じる
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(英語)
    • News Partner Program(英語)
    • Video Partner Program(英語)
    • セキュリティ報奨金プログラム(英語)
    • Security Research Device Program(英語)
    Open Menu Close Menu
    • Appleに相談
    • Apple Developer Center
    • App Store Awards(英語)
    • Apple Design Awards
    • Apple Developer Academy(英語)
    • WWDC
    Apple Developerアプリを入手する
    Copyright © 2025 Apple Inc. All rights reserved.
    利用規約 プライバシーポリシー 契約とガイドライン