セクション 104
List ビューを更新
LandmarkRow と同様に、LandmarkList はすでに macOS で機能していますが、改善点を使用することもできます。たとえば、お気に入りのみを表示するためのトグルスイッチをツールバーのメニューに移動すると、このメニューには、追加のフィルタリングコントロールを結合できます。
行う変更は macOS と iOS の両方で機能しますが、watchOS で対応するのは困難です。幸い、前のセクションでは、リストを watchOS 用の別のファイルに分割しました。
ステップ 1
MacLandmarks スキームに戻り、iOS と macOS をターゲットとする LandmarkList ファイルで、新しい toolbar 修飾子内に Menu を含む ToolbarItem を追加します。
アプリを実行するまで、toolbar の更新を確認することはできません。
プレビューその 1
LandmarkList.swift
- import SwiftUI
- struct LandmarkList: View {
@EnvironmentObject var modelData: ModelData
@State private var showFavoritesOnly = false
var filteredLandmarks: [Landmark] {
modelData.landmarks.filter { landmark in
(!showFavoritesOnly || landmark.isFavorite)
}
}
var body: some View {
NavigationView {
List {
Toggle(isOn: $showFavoritesOnly) {
Text("Favorites only")
}
ForEach(filteredLandmarks) { landmark in
NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark)
}
}
}
.navigationTitle("Landmarks")
.frame(minWidth: 300)
.toolbar {
ToolbarItem {
Menu {
} label: {
Label("Filter", systemImage: "slider.horizontal.3")
}
}
}
}
}
- }
- struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
LandmarkList()
.environmentObject(ModelData())
}
- }
ステップ 2
お気に入りの Toggle を Menu の中に移動します。
これにより、プラットフォーム固有の方法で toggle がツールバーの中に移動します。これには、ランドマークのリストがどれだけ長くなるか、またはユーザがどれだけ下にスクロールしてもアクセスできるようにするという追加の利点があります。
プレビューその 2
LandmarkList.swift
NavigationView {
List {
ForEach(filteredLandmarks) { landmark in
NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark)
}
}
}
.navigationTitle("Landmarks")
.frame(minWidth: 300)
.toolbar {
ToolbarItem {
Menu {
Toggle(isOn: $showFavoritesOnly) {
Label("Favorites only", systemImage: "star.fill")
}
} label: {
Label("Filter", systemImage: "slider.horizontal.3")
}
}
}
利用可能なスペースが増えたら、landmarks のリストをカテゴリでフィルタリングするための新しいコントロールを追加しましょう。
ステップ 3
FilterCategory 列挙体を追加して、フィルターの状態を記述します。
case 文字列をランドマーク構造体内の Category 列挙型と一致させて比較できるようにして、すべての case を含めてフィルタリングをオフにします。
LandmarkList.swift
@State private var showFavoritesOnly = false
enum FilterCategory: String, CaseIterable, Identifiable {
case all = "All"
case lakes = "Lakes"
case rivers = "Rivers"
case mountains = "Mountains"
var id: FilterCategory { self }
}
var filteredLandmarks: [Landmark] {
modelData.landmarks.filter { landmark in
ステップ 4
filter 状態変数を追加しますが、デフォルトではすべての case です。
フィルタの状態をリストビュー内に保存することで、ユーザはそれぞれ独自のフィルタ設定を持つ複数のリストビューウィンドウを開いて、さまざまな方法でデータを表示できます。
LandmarkList.swift
@EnvironmentObject var modelData: ModelData
@State private var showFavoritesOnly = false
@State private var filter = FilterCategory.all
enum FilterCategory: String, CaseIterable, Identifiable {
ステップ 5
特定の landmark のカテゴリと組み合わせて、新しい filter 設定を考慮に入れるように filteredLandmarks を更新します。
LandmarkList.swift
var filteredLandmarks: [Landmark] {
modelData.landmarks.filter { landmark in
(!showFavoritesOnly || landmark.isFavorite)
&& (filter == .all || filter.rawValue == landmark.category.rawValue)
}
}
ステップ 6
メニューに Picker を追加して、フィルタカテゴリを設定します。
フィルタには数個のアイテムしかないため、InlinePickerStyle を使用して、それらをすべて一緒に表示します。
LandmarkList.swift
ToolbarItem {
Menu {
Picker("Category", selection: $filter) {
ForEach(FilterCategory.allCases) { category in
Text(category.rawValue).tag(category)
}
}
.pickerStyle(InlinePickerStyle())
Toggle(isOn: $showFavoritesOnly) {
Label("Favorites only", systemImage: "star.fill")
}
} label: {
Label("Filter", systemImage: "slider.horizontal.3")
}
ステップ 7
filter の状態に一致するように navigation title (ナビゲーションタイトル) を更新します。
この変更は、iOS アプリで役立ちます。
LandmarkList.swift
&& (filter == .all || filter.rawValue == landmark.category.rawValue)
}
}
var title: String {
let title = filter == .all ? "Landmarks" : filter.rawValue
return showFavoritesOnly ? "Favorite \(title)" : title
}
var body: some View {
NavigationView {
List {
ForEach(filteredLandmarks) { landmark in
NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark)
}
}
}
.frame(minWidth: 300)
.toolbar {
ToolbarItem {
Menu {
ステップ 8
広いレイアウト内の 2 番目のビューのプレースホルダーとして 2 番目の子供ビューを NavigationView に追加します。
2 番目の子供ビューを追加すると、サイドバーリストスタイルを使用するようにリストが自動的に変換されます。
プレビューその 3
LandmarkList.swift
Toggle(isOn: $showFavoritesOnly) {
Label("Favorites only", systemImage: "star.fill")
}
} label: {
Label("Filter", systemImage: "slider.horizontal.3")
}
}
}
Text("Select a Landmark")
}
}
- }
- struct LandmarkList_Previews: PreviewProvider {
ステップ 9
macOS ターゲットを実行し、メニューがどのように動作するかを確認します。
ステップ 10
Landmarks ビルドターゲットを選択し、ライブプレビューを使用して、新しいフィルタリングが iOS でも適切に機能することを確認します。
iOS でもサイドバーリストスタイルが使用されていることに注意してください。