SwiftUIを使用してスワイプ編集アクションを実装しようとしています。削除アクションと移動アクションはどちらも完璧に機能しますが、スワイプで編集アクションを有効にする方法がわかりません。
ユーザーがスワイプをアクティブにしてアクションを編集するときに編集画面を開きたいのですが。
これは私のコードです:
struct TableView : View {
@State var dataSource = DataSource()
var body: some View {
NavigationView {
List {
ForEach(dataSource.pokemons.identified(by: \.id)) { pokemon in
Text(pokemon.name)
}
.onDelete(perform: deletePokemon)
.onMove(perform: movePokemon)
}
.navigationBarItems(leading: EditButton(), trailing: Button(action: addPokemon, label: { Text("Add") }))
.navigationBarTitle(Text("Pokemons"))
}
}
代わりにEditButton()を使用する必要があります。リストコンポーネントの編集モードを有効にします。
現時点では可能ではないと思います。
私が持っている最良の提案は、UITableView
プロトコルを介してUIViewRepresentable
を使用して独自のソリューションをロールすることです。そうは言っても、そこには実行可能なオープンソースのソリューションがあるかもしれません。
UITableView
はさまざまなプラットフォームでサポートされている「ジェネリック」タイプであるため、必要なすべてのList
機能を期待するのは危険だと思います。 UITableView
の一部の機能がList
に到達しない場合があります。
これは私が入力した簡単なコードですが、カスタムUITableView
ソリューションを作成する方法の簡単な例を示しています。
RoutineTableView(routines: routineDataSource.routines)
.trailingSwipeActionsConfiguration {
let editAction = UIContextualAction(
style: .normal,
title: "EDIT"
) { (action, sourceView, completionHandler) in
completionHandler(true)
}
editAction.backgroundColor = UIColor.darkGray
let deleteAction = UIContextualAction(
style: .destructive,
title: "DELETE"
) { (action, sourceView, completionHandler) in
completionHandler(true)
}
let actions = [deleteAction, editAction]
let configuration = UISwipeActionsConfiguration(actions: actions)
return configuration
}
.onCellPress {
print("hi there")
}
.navigationBarTitle("Routines")
private class CustomDataSource<SectionType: Hashable, ItemType: Hashable>: UITableViewDiffableDataSource<SectionType, ItemType> {
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
}
struct RoutineTableView: UIViewRepresentable {
let routines: [Routine]
private var onCellPress: (() -> Void)? = nil
private var trailingSwipeActionsConfiguration: (() -> UISwipeActionsConfiguration)? = nil
init(routines: [Routine]) {
self.routines = routines
}
func makeUIView(
context: UIViewRepresentableContext<RoutineTableView>
) -> UITableView {
let tableView = UITableView()
context.coordinator.update(withTableView: tableView)
return tableView
}
func updateUIView(_ uiView: UITableView, context: UIViewRepresentableContext<RoutineTableView>) {
context.coordinator.update(routines: routines)
}
// MARK: - Coordinator
func makeCoordinator() -> RoutineTableView.Coordinator {
return Coordinator(self)
}
class Coordinator: NSObject, UITableViewDelegate {
private enum Section {
case first
}
private let view: RoutineTableView
private var dataSource: UITableViewDiffableDataSource<Section, Routine>?
init(_ view: RoutineTableView) {
self.view = view
super.init()
}
func update(withTableView tableView: UITableView) {
tableView.register(RoutineTableViewCell.self)
tableView.delegate = self
let dataSource = CustomDataSource<Section, Routine>(tableView: tableView) { (tableView, indexPath, routine) -> UITableViewCell? in
let cell: RoutineTableViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(withRoutine: routine)
return cell
}
self.dataSource = dataSource
}
func update(routines: [Routine]) {
var snapshot = NSDiffableDataSourceSnapshot<Section, Routine>()
snapshot.appendSections([.first])
snapshot.appendItems(routines)
dataSource?.apply(snapshot, animatingDifferences: true)
}
// MARK: - <UITableViewDelegate>
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
view.onCellPress?()
}
func tableView(
_ tableView: UITableView,
trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath
) -> UISwipeActionsConfiguration? {
return view.trailingSwipeActionsConfiguration?()
}
}
}
extension RoutineTableView {
func onCellPress(
_ onCellPress: @escaping () -> Void
) -> RoutineTableView {
var view = self
view.onCellPress = onCellPress
return view
}
func trailingSwipeActionsConfiguration(
_ trailingSwipeActionsConfiguration: @escaping () -> UISwipeActionsConfiguration
) -> RoutineTableView {
var view = self
view.trailingSwipeActionsConfiguration = trailingSwipeActionsConfiguration
return view
}
}
うわー!うーん、EditButton()を使用するかどうかはわかりません。
私はあなたがリストを持っていて、行をスワイプして削除する選択肢を右に表示したいと思いますか?
リストのクロージャの後に.onDelete(perform: delete)
を実装するだけです。次に、クロージャーを処理する削除関数を定義する構造に関数を追加します。関数は次のように定義されることに注意してください:func delete (at offsets: IndexSet) {}
私が提案したものを追加して、関数本体が完了していなくてもコンパイルし(つまり、print()プレースホルダーを追加)、削除のスワイプ動作を確認できます。