はじめに
SwiftUIのListサンプル集(見た目編)の操作編です。
主に下記の記事で書いていたことの SwiftUI の List
版についてです。
複数選択1 | 複数選択2 | 一部選択服 | セル編集 |
---|---|---|---|
メニュー | 単一選択1 | 単一選択2 |
---|---|---|
アコーディオン | スクロール |
---|---|
複数選択
セルの複数選択処理です。
パターン1
こんな感じ。
List
の selection
は使わずにボタンを用意してチェックマークを出し分ける方法です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
private let rows = Array(0...10) @State private var selections = Set<Int>() List(rows, id: \.self) { row in Button { if selections.contains(row) { selections.remove(row) } else { selections.insert(row) } } label: { HStack { Text("Row: \(row)") if selections.contains(row) { Spacer() Image(systemName: "checkmark") .foregroundColor(.blue) } } } } |
パターン2
こんな感じ。
List
の selection
を使う方法です。編集モードにする必要があります。
1 2 3 4 5 6 7 |
private let rows = Array(0...10) @State private var selections = Set<Int>() List(rows, id: \.self, selection: $selections) { row in Text("Row: \(row)") } .environment(\.editMode, .constant(.active)) |
一部のセル選択不可
こんな感じ。
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 |
struct Item: Identifiable { let id = UUID() let selectable: Bool } private let items: [Item] = [ .init(selectable: true), .init(selectable: true), .init(selectable: false), .init(selectable: true), .init(selectable: false) ] @State private var selection: UUID? List { ForEach(items) { item in if item.selectable { Button { selection = item.id } label: { Text("Selectable") }.listRowBackground(selection == item.id ? Color(.systemGray4) : Color(.white)) } else { Text("Unselectable") } } } |
セルの編集
こんな感じ。
削除
編集モードにする必要がある。
1 2 3 4 5 6 7 8 9 |
List { ForEach(items) { item in Text(item.name) .deleteDisabled(false) }.onDelete { indexSet in items.remove(atOffsets: indexSet) } } .toolbar { EditButton() } |
下記を使う。
移動
編集モードにする必要がある。
1 2 3 4 5 6 7 8 9 10 |
List { ForEach(items) { item in Text(item.name) .moveDisabled(false) }.onMove { (indexSet, index) in items.move(fromOffsets: indexSet, toOffset: index) } } .toolbar { EditButton() } |
下記を使う。
移動先を不可にするのはできなさそう?
追加
UITableViewCell.EditingStyle.insert
相当のやつはなさそう?
下記のようにするとそれっぽい緑の追加ボタンを表示できる。ただ編集モードのときのインデントがあわない。。。
1 2 3 4 5 6 7 |
Button { // 追加処理 } label: { Image(systemName: "plus.circle.fill") .font(.system(size: 22)) .foregroundColor(Color(.systemGreen)) } |
ロングタップでメニュー表示
こんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
private let rows = Array(0...10) List(rows, id: \.self) { row in Text("Row: \(row)").contextMenu { Button("♥️ - Hearts", action: selectHearts) Button("♣️ - Clubs", action: selectClubs) Button("♠️ - Spades", action: selectSpades) Button("♦️ - Diamonds", action: selectDiamonds) } } private func selectHearts() { print(#function) } private func selectClubs() { print(#function) } private func selectSpades() { print(#function) } private func selectDiamonds() { print(#function) } |
deprecated らしい。。。
contextMenu(_:)
インデックスバー
List
にはないようです。
こんな感じで自作するしかないのかも?
SwiftUI List with Section Index on right hand side?
スワイプ
iOS 15 からは下記でできそう。
swipeActions(edge:allowsFullSwipe:content:)
アコーディオン
UITableView
の場合は自作で頑張らないといけなかったけどサクッとできる模様。
こんな感じ。
多階層もらくらく。
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 29 30 31 32 33 34 35 36 37 38 39 40 41 |
struct FileItem: Identifiable { let id = UUID() var name: String var children: [FileItem]? = nil var isDirectory: Bool { return children != nil } } private let files: [FileItem] = [ FileItem(name: "AAA", children: [ FileItem(name: "BBB", children: [ FileItem(name: "CCC", children: [ FileItem(name: "test_001.txt"), FileItem(name: "test_002.txt") ]), FileItem(name: "DDD", children: [ FileItem(name: "test_003.txt") ]), FileItem(name: "EEE", children: []) ]), FileItem(name: "FFF", children: [ FileItem(name: "GGG", children: [ FileItem(name: "HHH", children: [ FileItem(name: "III", children: [ FileItem(name: "test_004.txt") ]) ]) ]) ]) ]), FileItem(name: "test_005.txt", children: nil) ] List(files, children: \.children) { item in HStack { Image(systemName: item.isDirectory ? "folder.fill" : "doc.text.fill") .foregroundColor(Color(.systemBlue)) Text(item.name) } } |
単一選択
パターン1
こんな感じ。
List
の selection
を使わずにボタンを使う方法です。
1 2 3 4 5 6 7 8 9 10 11 12 |
private let rows = Array(0...10) @State private var selection: Int? List { ForEach(rows, id: \.self) { row in Button { selection = row } label: { Text("Row: \(row)") }.listRowBackground(selection == row ? Color(.systemGray4) : Color(.white)) } } |
パターン2
こんな感じ。
List
の selection
を使う方法です。編集モードにする必要があります。
1 2 3 4 5 6 |
private let rows = Array(0...10) @State private var selection: Int? List(rows, id: \.self, selection: $selection) { row in Text("Row: \(row)") } .environment(\.editMode, .constant(.active)) |
指定場所にスクロール
こんな感じ。
UITableView
の scrollToRow
のようなものが List
にはないのでちょっとゴニョゴニョする必要がある模様。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
private let rows = Array(0...100) ScrollViewReader { proxy in List(rows, id: \.self) { row in Text("Row: \(row)").id(row) } VStack(spacing: 16) { Button("Scroll to Top") { withAnimation { proxy.scrollTo(rows.first!, anchor: .top) } } Button("Scroll to Bottom") { withAnimation { proxy.scrollTo(rows.last!, anchor: .top) } } Button("Scroll to Random") { withAnimation { proxy.scrollTo(rows.randomElement()!, anchor: .top) } } } } |
おわりに
これでわりと List
を使えるようになったんじゃないかと思います。一覧表示ができるようになればだいたいのアプリをつくれるようになったといっても過言じゃない!!!
コメント