目次
概要
Listを実装したが、左スワイプして削除、右スワイプしてピン留めなどのように
ユーザーに優しい実装をするのも大事になってくる。わざわざボタン幾つもボタンを設置するのも見栄えが悪くなるし…
そんなリストの左右のスワイプで特定の処理を行う時は、swipeActionsを使用しよう!
ソースコード
アプリの最初の実行部分
TestApp.swift
import SwiftUI
@main
struct TestApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ListMenuView()
}
}
}
SwiftView表示部分
ListMenuView.swift
import SwiftUI
struct ListMenuView: View {
@ObservedObject private var viewModel: ListMenuViewModel = ListMenuViewModel()
var body: some View {
NavigationView {
VStack {
listView()
}
.navigationTitle("リストの備忘録動作確認")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
listOrderMenu()
}
}
}
}
private func listView() -> some View {
return List {
ForEach(Array(viewModel.dataList.enumerated()), id: \.offset) { index, data in
Button {
print("\(data)をタップしました。")
} label: {
Text(data)
}
.swipeActions(edge: .trailing) {
Button(role: .destructive) {
viewModel.deleteData(index: index)
} label: {
Image(systemName: "trash.fill")
}
}
.swipeActions(edge: .leading) {
Button(role: .cancel) {
viewModel.bringTop(index: index)
} label: {
Image(systemName: "pin.fill")
}
.tint(.green)
}
.contextMenu(menuItems: {
cellMenu(index: index)
})
}
}
}
private func cellMenu(index: Int) -> some View {
return VStack {
Button {
print("編集する?")
} label: {
Text("編集")
}
Button {
viewModel.deleteData(index: index)
} label: {
Text("削除")
.foregroundColor(.red)
}
}
}
private func listOrderMenu() -> some View {
return Menu {
ForEach(DataOrder.allCases, id:\.self) { dataOrder in
Button {
viewModel.sortDataOrder(selectedOrder: dataOrder)
} label: {
HStack {
if dataOrder == viewModel.selectedOrder {
Image(systemName: "checkmark")
}
Text(dataOrder.rawValue)
}
}
}
} label: {
Image(systemName: "arrow.up.and.down.text.horizontal")
}
}
}
Swift処理部分
ListMenuViewModel.swift
import Foundation
enum DataOrder: String, CaseIterable, Identifiable {
case titleAscendingOrder = "項目名の昇順"
case titleDescendingOrder = "項目名の降順"
var id: String { rawValue }
}
class ListMenuViewModel: ObservableObject {
@Published private(set) var dataList: [String]
@Published private(set) var selectedOrder: DataOrder = .titleAscendingOrder
init() {
dataList = []
for index in 0 ..< 20 {
dataList.append("データ\(index)")
}
}
func sortDataOrder(selectedOrder: DataOrder) {
self.selectedOrder = selectedOrder
switch selectedOrder {
case .titleAscendingOrder:
dataList = dataList.sorted(by: {$0 < $1})
case .titleDescendingOrder:
dataList = dataList.sorted(by: {$1 < $0})
}
}
func deleteData(index: Int) {
dataList.remove(at: index)
}
func bringTop(index: Int) {
let moveData = dataList.remove(at: index)
dataList.insert(moveData, at: 0)
}
}
Swiftスクリーンショット
詳細
スワイプの方向と、その方向に応じて表示させるボタンの実装をする際、swipeActionsで以下のように書く。
.swipeActions(edge: /* スワイプの方向 */) {
Button(role: /* ボタンの役割 */) {
// ボタンの処理
} label: {
// 表示させたいアイコン
}
}
スワイプの方向
設定値 | 内容 |
.leading | セルを右にスワイプさせた時に表示するボタン。 ピン留めやお気に入りなどで実装されることが多い。 セルの左側に並ぶボタン群。 |
.trailing | セルを左にスワイプさせた時に表示するボタン。 削除ボタンなどで実装されることが多い。 セルの左側に並ぶボタン。 |
ボタンの役割
設定値 | 内容 |
cancel | 一定以上の量をスワイプするとボタンが非表示になる。 ボタンの背景色はデフォルトは明るいグレー。 |
destructive | 一定以上の量をスワイプするとデータの削除処理が行われる。 ボタンの背景色のデフォルトは赤。 |
ボタンの背景色の変更
このボタンの背景色はZStackを使うわけでも、foregroundColorを設定するわけでもない。
Buttonの最後に以下を追加することで色の設定ができる。
.tint(/* 設定したい背景色 */)
参考ページ:
stackoverflow「Set image color in SwipeAction」
.NET ゆる〜りワーク【SwiftUI】List にスワイプアクション(.swipeActions)を実装する【iOS15&Xcode13】