Listで選択された要素の取得
List(_:selection:) + Identifiable.ID を使う
|
1 2 3 4 5 |
@State private var selectedID: ScreenshotItem.ID? List(items, selection: $selectedID) { item in Text("item") } |
モデル
|
1 2 3 4 |
struct ScreenshotItem: Identifiable, Hashable { let id = UUID() let cgImage: CGImage } |
View
|
1 2 3 4 5 6 7 8 9 10 |
@State private var screenshots: [ScreenshotItem] = [] @State private var selectedID: ScreenshotItem.ID? List(screenshots, selection: $selectedID) { item in Image(decorative: item.cgImage, scale: 2.0) .resizable() .scaledToFit() .frame(height: 80) } .listStyle(.sidebar) |
選択された「実体」を取得
|
1 2 3 |
var selectedItem: ScreenshotItem? { screenshots.first { $0.id == selectedID } } |
複数選択の場合
|
1 2 3 4 5 |
@State private var selection = Set<ScreenshotItem.ID>() List(screenshots, selection: $selection) { item in Text("SS") } |
実体取得
|
1 2 3 |
let selectedItems = screenshots.filter { selection.contains($0.id) } |
「クリック時に即処理したい」場合
onChange を使う
|
1 2 3 4 5 |
.onChange(of: selectedID) { _, newValue in guard let id = newValue else { return } let item = screenshots.first { $0.id == id } // メインに反映、加工開始など } |
選択された要素の削除の例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Button(action: { guard let id = selected_item else { return } // 選択されている要素を削除 SS_images.removeAll { $0.id == id } // 選択状態をクリア selected_item = nil image = nil }) { Image(systemName: "trash.circle") .resizable() .foregroundColor(Color(.blue)) .frame(width: 20, height: 20) } |
複数選択にする例
複数選択を有効にするには、Listに.selectionDisabled(false)を追加するだけでは不十分です。以下の修正が必要です:
修正箇所
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
struct ScreenshotSidebarView: View { @Binding var capture_image: CGImage? @Binding var SS_images: [ScreenshotItem] @Binding var selected_item: Set<ScreenshotItem.ID> // ← ? を削除(常にSetを持つ) @State private var trash_flg: Bool = false var selected_image: CGImage? { guard let firstID = selected_item.first else { return nil } // ← selected_itemは常にSetなので guard let 不要 return SS_images.first { $0.id == firstID }?.cg_image } var multiple_selected_image: [ScreenshotItem] { return SS_images.filter { selected_item.contains($0.id) } // ← シンプルに } var body: some View { HStack { List(SS_images, selection: $selected_item) { item in Image(decorative: item.cg_image, scale: 2.0) .resizable() .scaledToFit() .frame(height: 80) .padding(4) } .listStyle(.sidebar) // ← ここに何も追加しなくてOK |
重要なポイント
@Binding var selected_item: Set<ScreenshotItem.ID>- macOSでは自動的に複数選択が有効
ScreenshotItemがIdentifiableに準拠している必要がある
|
1 2 3 4 5 |
struct ScreenshotItem: Identifiable { let id: UUID let cg_image: CGImage // ... } |
親ビューでの使い方
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
struct ParentView: View { @State private var SS_images: [ScreenshotItem] = [] @State private var selected_item: Set<ScreenshotItem.ID> = [] // ← 空のSetで初期化 @State private var capture_image: CGImage? var body: some View { ScreenshotSidebarView( capture_image: $capture_image, SS_images: $SS_images, selected_item: $selected_item ) } } |
選択状態の確認
|
1 2 3 4 5 6 7 |
// 選択数を表示 Text("選択数: \(selected_item.count)") // 選択されているか確認 if !selected_item.isEmpty { Text("選択中") } |
これでCommandキーやShiftキーを使った複数選択ができるようになります!試してみてください。
.onMove()でインデックスを取得する
SwiftUIのListで.onMove(perform:)を使用する際、移動前(ドラッグ開始時)のインデックスは、クロージャの引数であるIndexSetから取得できます。
具体的には、IndexSetのfirstプロパティを使って取得するのが最も簡単です。 [1]
実装方法
onMoveの第1引数(通常sourceまたはindicesと名付けられます)が、移動された要素のインデックスセットです。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import SwiftUI struct ContentView: View { @State private var items = ["Item 1", "Item 2", "Item 3", "Item 4"] var body: some View { NavigationView { List { ForEach(items, id: \.self) { item in Text(item) } .onMove(perform: move) // 1. onMoveを設定 } .toolbar { EditButton() } } } // 2. 移動処理メソッド func move(from source: IndexSet, to destination: Int) { // --- 移動前のインデックスを取得 --- let fromIndex = source.first! print("移動前インデックス: \(fromIndex)") print("移動元アイテム: \(items[fromIndex])") // 配列のデータを並べ替える items.move(fromOffsets: source, toOffset: destination) } } |
ポイント
IndexSetから取得:onMove(perform: { source, destination in ... })のsourceはIndexSet型です。source.first: 通常、単一のアイテム移動であればsource.firstで移動前のインデックス(0から始まるInt)を取得できます。- 移動の実行:
items.move(fromOffsets:toOffset:)メソッドを使用して、配列内のデータを実際に移動させます。
コメント