ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
UIKitでSwiftUIを使用する
UIKit Appで、SwiftUIの機能を活用する方法を紹介します。UIHostingConfigurationを使用したSwiftUIで、カスタムUICollectionViewセルやUITableViewセルをシームレスに構築することができます。また、App内でのUIKitとSwiftUIのコンポーネント間におけるデータフローを管理する方法も紹介します。 このセッションを最大限に活用するには、SwiftUIに関する基本的な知識を習得しておくとよいでしょう。
リソース
- Managing model data in your app
- selfSizingInvalidation
- selfSizingInvalidation
- UIHostingConfiguration
- UIHostingController
- UIViewController
- Using SwiftUI with UIKit
関連ビデオ
WWDC22
WWDC20
-
ダウンロード
♪メロウなヒップホップ ♪ ♪ Sara Frederixonです Health Appのエンジニアです 今日はSwiftUIとUIKitの話をします 私も皆さん同様に既存のUIKitを使います それが私にとってヘルスケアAppです このAppは多くのデータを表示し 健康に関するデータを分かりやすく表示します でもこの構築は複雑です SwiftUIを最大限活かす事に注力してきました そこでUIKitとSwiftUIチームと組んだ 同一Appにこれらをいかに組み込むかお話します このビデオで説明するのはいかに簡単に 自分のUIKitAppでSwiftUIを使うかです まずより柔軟性を与える 新しいアップデートを加えた 既存のUIHostingControllerを説明し 次にAppに既に存在するデータを SwiftUIビューに入力し そのデータが変更されたときに SwiftUIビューを確実に更新する方法について 掘り下げます それからSwiftUIを使って UICollectionViewとUITableViewの セルを構築することができる エキサイティングな新機能について話します 最後にセル内でSwiftUIを使用しているときに コレクションとテーブルビューでデータの流れの ユニークな側面について説明します ではまずUIHostingControllerの話を UIHostingControllerは SwiftUIビュー階層を含むUIViewControllerです ホスティングコントローラーを使って作業します どこでもUIKitの ビューコントローラーが使える UIHostingControllerは SwiftUIへアクセスする最も便利な手段です ホスティングコントローラーの機能を見てみましょう ホスティングコントローラは ビューコントローラであり そのviewプロパティに UIViewが格納されていることを意味します そのビュー内で SwiftUIコンテンツがレンダリングされます 使用例を見てみましょう HeartRateViewとSwiftUI ビューを作成します 次にHeartRateViewでコントローラーを作成し これがルートビューになります UIHostingControllerは全UIKitの ビューコントローラーのAPIで使えます 他の例を見てみましょう 前回と同じHeartRateViewと ホスティングコントローラーを用意しました ここでホスティングコントローラーを チャイルドビューコントローラーとして 追加します コントローラービューで ポジションとサイズを設定します UIHostingController 内の SwiftUI のコンテンツが変更されたとき ビューのサイズを変更する必要が 生じることがあります iOS 16の新機能としてUIHostingControllerで ビューコントローラーの優先コンテンツサイズと ビューの固有コンテンツサイズの自動更新を 有効にすることができます 有効化はUIHostingControllerの sizingOptionsで行います 例を見てみましょう まずHeartRateViewを作成します そしてhostingControllerも作成 新しい sizingOptions API を使って hostingController に preferredContentSize を 自動的に更新するように指示します 次にポップオーバーに設定するのは modalPresentationStyleです 新しいsizingOptionsのAPIがポップオーバーを SwiftUIのコンテンツへ常に最適化します UIHostingControllerを学んだところで 他のUIKitからSwiftUIへの データの追加についてお話します そしてデータ変更時SwiftUIが 更新される流れも これはUIKitのダイアグラムです ここには既存のモデルレイヤーがあります 通常Appデータのモデル オブジェクトを格納します Appには複数のビューコントローラーが SwiftUIの使用開始は ビューコントローラー内の SwiftUIビューと ホスティングコントローラーが必要です このSwiftUIビューとデータを集積します 既存のモデルレイヤーに属するものです ここではデータがUIKitとSwiftUIを繋げるか 見ていきます SwiftUIは様々なデータのプリミティブを 提供します App内のデータ管理の為です 他のオプションも見てみましょう SwiftUIで作成したデータの保存は SwiftUIが @Stateと@StateObjectを提供します SwiftUI外のデータにフォーカスしている為 このプロパティラッパーは正しくありません これについてここでは触れません “Swift UIにおけるデーターの重要項目”の ビデオでSwiftUIビュー内のデータが学べます SwiftUI外でデータを扱うには ビューを初期化した際に値を処理します Raw dataを処理しているからです これはSwiftUIが管理するものではありません データ変更時UIHostingControllerを マニュアルで更新する必要があります 例を見てみましょう HeartRateViewというSwiftUI です シングルプロパティで 心拍数をbeatsPerMinuteで保存しています これをテキストでValueとして表示します ここでHeartRateViewを UIHostingControllerで View controllerに表示します 対象はHeartRateViewControllerです レファレンスをホスティングコントローラーに保存します これで後でroot viewを更新できます SwiftUIのHeartRateViewは値型なので それ自体を保存すると別のコピーが作成され UIを更新することができないことを 覚えておいてください HeartRateViewControllerは HeartRateViewに入力するためのデータを 所有しています このデータはbeatsPerMinuteプロパティに 格納され beatsPerMinuteの値が変化したら メソッドを呼び出してビューを更新しています updateメソッドの内部で 最新のbeatsPerMinuteの値を使用して 新しいHeartRateViewを作成し そのビューをホスティングコントローラの rootViewとして割り当てます これはUIKitからSwiftUIにデータを取得する シンプルな方法ですが データが変更されるたびに ホスティングコントローラのrootViewを 手動で更新する必要があります これらの更新を自動的に行うために 他のSwiftUIデータプリミティブを いくつか見ていきましょう @ObservedObjectと@EnvironmentObjectの プロパティラッパーsが ObservableObjectプロトコルに準拠した 外部モデルObjectの参照を許可します これらのプロパティラッパーを使うと データが変更されたとき SwiftUIは自動的にビューを更新します このビデオでは@ObservedObjectの プロパティラッパーをお見せしました EnvironmentObjectについては 先ほど紹介したセッションをご覧ください “Swift UIにおけるデーターの重要項目”です @ObservedObjectの作成を見てみましょう まず既存のモデルオブジェクトを ObservableObjectプロトコルに 準拠させることからはじめます 次にSwiftUI ビューの @ObservedObject プロパティとして モデルを保存します ObservableObjectをSwiftUIに接続することで そのプロパティの1つが変更されたときに ビューを更新することができます HeartRateViewのサンプルに戻り これを配線してみましょう このAppは beatsPerMinuteというプロパティを持った HeartDataというクラスを持っています これをObservableObjectプロトコルに 準拠させます 次にbeatsPerMinuteプロパティに @Publishedプロパティラッパーを追加します このプロパティラッパーは 変更時にビューを更新するために SwiftUI をトリガーするものです HeartRateViewでは @ObservedObjectプロパティラッパーで アノテーションされたプロパティに HeartDataを格納しています ビュー本体ではHeartDataから 直接beatsPerMinuteを表示しています ではこれらをビューコントローラーで 一緒に使ってみましょう 以下がHeartRateViewControllerです HeartData ObservableObjectを プロパティに保存します このプロパティはSwiftUIビューの 内部ではないので ここでプロパティラッパーを 使用する必要はありません HeartRateViewControllerは HeartDataのインスタンスで初期化され それを使ってHeartRateViewを作成し ホストコントローラのrootViewとします ダイアグラムはこの結合を表しています 現在のHeartDataインスタンスを取得すると 78拍/分の心拍数が含まれています そしてそのHeartDataのインスタンスで 新しいHeartRateViewControllerを作成し SwiftUIのHeartRateViewに接続するのです 数秒後 次の心拍データサンプルが到着すると 心臓データのbeatsPerMinuteプロパティは 94に更新されます これはObservableObjectの 公開プロパティを変更するため HeartRateViewは自動的に更新され 新しい値が表示されます データ変更時にホスティングコントローラーで マニュアルで更新する必要はありません これがObservableObjectが UIKitからSwiftUIにデータを橋渡しする 素晴らしい方法である理由です 次にコレクションビューと テーブルビューのセルでの SwiftUIの使用について説明します iOS 16の新機能である UIHostingConfigurationは 既存のUIKitのコレクションビューと テーブルビューの中で SwiftUIの利用を可能にしました UIHostingConfiguration を使うと 余分なビューやビューコントローラーを 使わずに SwiftUIでカスタムセルを 簡単に実装することができます UIHostingConfigurationについて 深く掘り下げる前に UIKitのセルコンフィギュレーションについて おさらいしておきましょう セルコンフィギュレーションはUIKitでセルの コンテンツ・スタイル・アクションを定義する 最新の方法です UIViewやUIViewControllerと違い コンフィギュレーションは軽いstructです この作成は高価ではありません コンフィギュレーションはあくまで セルの外観を表すものなので 効果を発揮するためには セルに適用する必要があります コンフィギュレーションは互換性があり UICollectionViewと UITableViewの両方のセルで機能します 詳細は”モダンなセルの構成”をご覧ください これを念頭に置いて UIHostingConfigurationの話をしましょう UIHostingConfigurationは コンテントコンフィギュレーションで SwiftUIのViewBuilderで初期化します つまりSwiftUIでコードを書き始め 内部で直接Viewを作成します ホスティングコンフィギュレーションの レンダリングには UICollectionViewかUITableViewの cell.contentConfigurationプロパティに 設定します カスタムの心拍セルを構築するために このホスティングコンフィギュレーションで SwiftUIのコードを書き始めましょう “Heart Rate”というテキストと 心臓の画像を持つ ラベルを作成することから始めます SwiftUI のビューは それらが使われるコンテキストに基づく デフォルトのスタイルを受け取ります しかしSwiftUIの標準的な ビューモディファイアを使用して スタイリングのカスタマイズを 始めることができます ラベルにforegroundStyleとfont修飾子をつけて 画像と文字を太いフォントでピンクにしましょう 通常のSwiftUIのコードを書いているだけなので いつでも好きなときにコードを スタンドアロンビューにすることができます ここではHeartRateTitleViewという 新しいSwiftUIビューを作成し 持っていたコードをそのボディに移動し そのHeartRateTitleViewを ホスティングコンフィギュレーションで 使用しています セルに示すように 全く同じ結果が得られます これでHeartRateTitleViewの中に さらにビューを追加していくことが できるようになりました ラベルをHStackの中にスペーサー付きで入れ その横にTextビューで 現在時刻を追加しています いい具合です では更にcustom cellにコンテンツを加えます HeartRateTitleViewの下に書きましょう ここではVStackを HeartRateTitleViewの下にあるカスタムセルに さらにコンテンツを追加してみましょう 次に90 BPMを表示するために 2つのTextビューをHStackにまとめ いくつかのモディファイアを適用して 好きなようにスタイルを設定します HeartRateTitleViewで前に行ったのと同様 この新しいコードを独自のSwiftUIビューに 移動させることができます 今度は同じコードを HeartRateBPMViewの本体に展開します セルもいい感じですが もう1つ追加できるアイデアがあります iOS 16の新機能は わずか数行のコードでデータを 美しいグラフで視覚化できる Swift Chartsフレームワークです これを利用してセルの中に 小さな折れ線グラフを表示させてみましょう 新しいチャートビューを使用して 最近の心拍数サンプルを視覚化する 小さなラインチャートを作成し セル内のBPMビューの隣に表示します グラフを生成するために 心拍数のサンプルのコレクションを渡し すべてのサンプルを結ぶLineMarkを描画します 各サンプルを示す円記号をライン上に追加し ピンクの前景スタイルを適用して HeartRateTitleViewにマッチするように チャートを着色することができます 新しい Swift Charts フレームワークで できることの表面を削ったに過ぎません 「Swift Chartsの紹介」 のセッションで 詳細を紹介しています 完成した心拍計は 見た目が素晴らしいだけでなく たった数分で簡単に作ることができました それだけUIHostingConfiguration と SwiftUI を使って カスタムセルを作り始めるのは簡単なことです UIHostingConfigurationがサポートする 4つの特別な機能について説明しましょう デフォルトではルートレベルのSwiftUIコンテンツは UIKitのセルのレイアウトマージンに基づいて セルのエッジから挿入されます これによりセルのコンテンツは 隣接するセルやナビゲーションバーなどの 他のUI要素のコンテンツと 適切に整列されるようになります 時には異なるマージンを使用したり セルの端までコンテンツを 拡張したい場合があります このような場合はUIHostingConfigurationの margin修飾子を使ってデフォルトのマージンを 変更することができます SwiftUI を使ってセルの背景の外観を カスタマイズしたい場合 UIHostingConfiguration の background モディファイアを使います UIHostingConfigurationの バックグランドとそのコンテントには いくつかの重要な違いがあります 背景はセルの背面セルのコンテンツビューで SwiftUIコンテンツの下にホストされます また一般的にコンテンツは セルの端から端まで入り込んでいますが 背景はセル内の端から端まで伸びています 最後にセルフサイズセルを使用する場合 セルの内容のみがセルのサイズに影響します 次にコレクションビューのリストやテーブルビューの 中にセルがある場合に使用できる UIHostingConfigurationの 特別な機能を2つ見てみましょう リストにおいてセルの下のセパレータは デフォルトでホスティングの設定で 自動的にSwiftUIテキストに整列されます この例ではセパレータの前縁が画像からはみ出し セル内のテキストと揃うようになっていることに 注目してください ホスティングの設定で セパレータを異なる SwiftUIビューに揃える必要がある場合は alignmentGuide修飾子を使用してください コレクションビューのリストや テーブルビューの内部では SwiftUIで直接 行のスワイプアクションを 設定することができます swipeActionsモディファイアの中に ボタンを作成することで セルをスワイプしてカスタムアクションを表示し 実行することができるようになります このビデオのサンプルコードをダウンロードすると 完全な例を見ることができます スワイプアクションを定義する際には ボタンがアイテムに対する安定した識別子を使用して アクションを実行することを確認してください インデックスパスを使用しないでください セルが表示されている間に インデックスパスが変更されると スワイプ操作が 間違ったアイテムに作用する可能性があります セルでUIHostingConfigurationを使用する場合 タップ処理・ハイライト・選択などの セルインタラクションは 依然としてコレクションビューまたは テーブルビューによって処理されることに 留意してください これらのUIKitのセルの状態の いずれかのために SwiftUI のビューを カスタマイズする必要がある場合 セルの configurationUpdateHandler の内部で ホスティングの設定を作成し SwiftUI のコードで提供される状態を 使用することができます ConfigurationUpdateHandlerは セルの状態が変化するたびに再度実行され 新しい状態のUIHostingConfigurationを作成し セルに適用します この例では状態を利用して セルが選択されたときに チェックマーク画像を追加しています UIHostingConfigurationについて理解できたら モデルレイヤーから SwiftUIを使ってセルを描画された UICollectionViewまたはUITableViewへの データの流れを管理する方法を説明しましょう 目指すのは健康状態の可視化です この例ではUICollectionViewを 使用していますが 私たちが議論するすべては UITableViewにも同様に適用されます コンポーネントを見てみましょう MedicalConditionモデルオブジェクトの コレクションを コレクションビューに表示します このコレクション内の各項目について その病状を表示するセルを コレクションビューに作成したい そのためにコレクションビューに接続された diffableデータソースを作成することにします 次にデータコレクション内の MedicalConditionモデルオブジェクトの 識別子を diffableデータソースのスナップショットに 入力する必要があります diffableデータソーススナップショットには MedicalConditionオブジェクトではなく 各MedicalConditionの一意の識別子が 含まれていることが重要です これによりdiffableデータソースは 各項目の同一性を正確に追跡し 後で新しいスナップショットを適用したときに 正しい変更を計算できるようになります これらの項目識別子を持つスナップショットを diffableデータソースに適用することで コレクションビューが自動的に更新され 各項目に新しいセルが作成されます それぞれのセルは UIHostingConfigurationのSwiftUIビューで 1つのMedicalConditionを表示するように 設定されています SwiftUIで構築されたセルを表示しているので データが変更されたときに UIを更新する処理を行う必要があります 変更には2種類あり 別々に処理する必要があります 1つ目のタイプは データ収集そのものが変化する場合です 例えば項目の挿入・並べ替え。削除が 行われたときです これらの変更はdiffableデータソースに 新しいスナップショットを適用することで処理されます Diffableデータソースは 新旧のスナップショットを差分し コレクションビューに必要な更新を行い セルの挿入・移動・削除を行います データのコレクション自体の変更は セル内部のものには影響しないので UIKitやSwiftUIを使ってセルを構築しても これらのタイプの変更を 同じように扱うことができます 2つ目は個々のモデルオブジェクトの プロパティが変更された場合です このような変更には多くの場合 既存のセルのビューを更新する必要があります diffableデータソースは スナップショットに アイテムの識別子しか含まれないため 既存のアイテムのプロパティが いつ変更されたかを 知ることはできません 従来UIKitを使用する場合 スナップショット内のアイテムを 再設定または再読み込みすることで これらの変更についてdiffableデータソースに 手動で伝える必要がありました しかしセルでSwiftUIを使用する場合 これはもう必要ありません SwiftUIビューのObservedObjectプロパティに ObservableObjectモデルを格納することで モデルの公開プロパティへの変更は 自動的にSwiftUIがビューを リフレッシュするトリガーとなります これはモデルとセル内のSwiftUIビューの間の 直接的な接続を確立します 変更が行われたとき diffableデータソースや UICollectionViewを通さずに セル内のSwiftUIビューは直接更新されます セルのデータが変更されると 新しい内容に合わせてセルを 拡大または縮小する必要が生じることがあります しかしSwiftUIのセルの内容が UIKitを通さずに直接更新される場合 どのようにコレクションビューはセルのサイズを 変更することを知るのでしょうか? UIHostingConfigurationは UIKitの全く新しい機能を利用して これを実現します iOS 16ではUICollectionViewとUITableViewの セルフ-サイジングのセルも セルフ-リサイズされるようになりました ! これはデフォルトで有効で UIHostingConfigurationを使っていて SwiftUI のコンテンツが変更されるとき 必要であればそれを含むセルが 自動的にリサイズされます この機能の詳細については ”UIKitの最新情報”をご覧ください もう一つデータフローを 処理する必要がある場合があります それはSwiftUIビューからAppの他の部分に データを送り返すことです ObservableObjectが全て担ってくれます ObservableObjectの公開プロパティに対して 双方向バインディングを作成することができます ObservableObjectからSwiftUIに データが流れるだけでなく SwiftUIはモデルオブジェクトのプロパティに 変更を書き戻すことができます ここではMedicalConditionセルの テキストを編集可能にすることで 双方向のバインディングを作成する 簡単な例を見てみましょう ObservableObjectとMedicalConditionです IDプロパティの固有のIdentifierです diffableデータソーススナップショットへの 入力に使用される識別子です そしてこの公開プロパティには 病状のテキストが格納されます 各セル内に病状テキストを表示する MedicalConditionViewです これは読み出しのみなので 編集可能にしましょう あとはTextViewをTextFieldに変更し ドル記号のプレフィックスを付けて MedicalConditionのtextプロパティへの バインディングを作成するだけです テキストフィールドに入力すると このバインディングによってSwiftUIは変更を ObservableObjectに直接書き戻せます SwiftUIで双方向のデータフローを 設定するのは本当に簡単です UIHostingController は SwiftUI のコンテンツを UIKit Appに埋め込むための強力な方法です SwiftUI のビューは ホスティングコントローラの ビューの内部でレンダリングされ UIKit でビューコントローラを 使うことができる場所であれば どこでもホスティングコントローラを 使うことができます UIHostingController を使用する場合は 必ずビューコントローラーを ビューと一緒にAppに追加してください ツールバー・キーボードショートカット UIViewControllerRepresentableを 使用するビューなどの多くのSwiftUIの機能は 適切に統合するために UIKit のビューコントローラ階層への 接続を必要とするので ホストコントローラのビューを ホストコントローラ自身から 決して切り離さないでください 比較のために セルに UIHostingConfiguration を適用するとき SwiftUI ビューは UIViewController なしで セルでホストされます UIHostingConfigurationは SwiftUIの機能の大部分をサポートします しかしUIViewControllerRepresentableに 依存するSwiftUIビューは セルの内部で使用できないことに 留意してください UIHostingController と UIHostingConfiguration を使って UIKit Appに SwiftUI を組み込むための 素晴らしい方法が2つあります SwiftUI は既存の UIKit アプリに シームレスに統合されます UIHostingController を使って App全体に SwiftUI を追加しましょう UIHostingConfigurationを使用して コレクションとテーブルビューに カスタムセルを作成します またObservableObjectを活用することで データとUIを常に同期させることができます 今すぐあなたのAppに SwiftUIを追加しましょう ありがとうございました
-
-
2:09 - Presenting a UIHostingController
// Presenting a UIHostingController let heartRateView = HeartRateView() // a SwiftUI view let hostingController = UIHostingController(rootView: heartRateView) // Present the hosting controller modally self.present(hostingController, animated: true)
-
2:31 - Embedding a UIHostingController
// Embedding a UIHostingController let heartRateView = HeartRateView() // a SwiftUI view let hostingController = UIHostingController(rootView: heartRateView) // Add the hosting controller as a child view controller self.addChild(hostingController) self.view.addSubview(hostingController.view) hostingController.didMove(toParent: self) // Now position & size the hosting controller’s view as desired…
-
3:13 - Presenting UIHostingController as a popover
// Presenting UIHostingController as a popover let heartRateView = HeartRateView() // a SwiftUI view let hostingController = UIHostingController(rootView: heartRateView) // Enable automatic preferredContentSize updates on the hosting controller hostingController.sizingOptions = .preferredContentSize hostingController.modalPresentationStyle = .popover self.present(hostingController, animated: true)
-
5:27 - Passing data to SwiftUI with manual UIHostingController updates
// Passing data to SwiftUI with manual UIHostingController updates struct HeartRateView: View { var beatsPerMinute: Int var body: some View { Text("\(beatsPerMinute) BPM") } } class HeartRateViewController: UIViewController { let hostingController: UIHostingController< HeartRateView > var beatsPerMinute: Int { didSet { update() } } func update() { hostingController.rootView = HeartRateView(beatsPerMinute: beatsPerMinute) } }
-
7:51 - Passing an ObservableObject to automatically update SwiftUI views
// Passing an ObservableObject to automatically update SwiftUI views class HeartData: ObservableObject { @Published var beatsPerMinute: Int init(beatsPerMinute: Int) { self.beatsPerMinute = beatsPerMinute } } struct HeartRateView: View { @ObservedObject var data: HeartData var body: some View { Text("\(data.beatsPerMinute) BPM") } }
-
8:30 - Passing an ObservableObject to automatically update SwiftUI views
// Passing an ObservableObject to automatically update SwiftUI views class HeartRateViewController: UIViewController { let data: HeartData let hostingController: UIHostingController<HeartRateView> init(data: HeartData) { self.data = data let heartRateView = HeartRateView(data: data) self.hostingController = UIHostingController(rootView: heartRateView) } }
-
9:52 - UIHostingConfiguration
cell.contentConfiguration = UIHostingConfiguration { // Start writing SwiftUI here! }
-
11:02 - Building a custom cell using SwiftUI with UIHostingConfiguration
// Building a custom cell using SwiftUI with UIHostingConfiguration cell.contentConfiguration = UIHostingConfiguration { HeartRateTitleView() } struct HeartRateTitleView: View { var body: some View { HStack { Label("Heart Rate", systemImage: "heart.fill") .foregroundStyle(.pink) .font(.system(.subheadline, weight: .bold)) Spacer() Text(Date(), style: .time) .foregroundStyle(.secondary) .font(.footnote) } } }
-
12:46 - Building a custom cell using SwiftUI with UIHostingConfiguration
// Building a custom cell using SwiftUI with UIHostingConfiguration cell.contentConfiguration = UIHostingConfiguration { VStack(alignment: .leading) { HeartRateTitleView() Spacer() HeartRateBPMView() } } struct HeartRateBPMView: View { var body: some View { HStack(alignment: .firstTextBaseline) { Text("90") .font(.system(.title, weight: .semibold)) Text("BPM") .foregroundStyle(.secondary) .font(.system(.subheadline, weight: .bold)) } } }
-
13:41 - Building a custom cell using SwiftUI with UIHostingConfiguration, with a chart!
// Building a custom cell using SwiftUI with UIHostingConfiguration cell.contentConfiguration = UIHostingConfiguration { VStack(alignment: .leading) { HeartRateTitleView() Spacer() HStack(alignment: .bottom) { HeartRateBPMView() Spacer() Chart(heartRateSamples) { sample in LineMark(x: .value("Time", sample.time), y: .value("BPM", sample.beatsPerMinute)) .symbol(Circle().strokeBorder(lineWidth: 2)) .foregroundStyle(.pink) } } } }
-
14:41 - Content margins
cell.contentConfiguration = UIHostingConfiguration { HeartRateBPMView() } .margins(.horizontal, 16)
-
15:16 - Cell backgrounds
cell.contentConfiguration = UIHostingConfiguration { HeartTitleView() } .background(.pink)
-
16:32 - List swipe actions
cell.contentConfiguration = UIHostingConfiguration { MedicalConditionView() .swipeActions(edge: .trailing) { … } }
-
17:25 - Incorporating UIKit cell states
// Incorporating UIKit cell states cell.configurationUpdateHandler = { cell, state in cell.contentConfiguration = UIHostingConfiguration { HStack { HealthCategoryView() Spacer() if state.isSelected { Image(systemName: "checkmark") } } } }
-
23:17 - Creating a two-way binding to data in SwiftUI
// Creating a two-way binding to data in SwiftUI class MedicalCondition: Identifiable, ObservableObject { let id: UUID @Published var text: String } struct MedicalConditionView: View { @ObservedObject var condition: MedicalCondition var body: some View { HStack { Spacer() } } }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。