web-dev-qa-db-ja.com

SwiftUIを使用してリストのスワイプでアクションを編集できるようにする方法は?

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"))
        }
}
8
czater

代わりにEditButton()を使用する必要があります。リストコンポーネントの編集モードを有効にします。

1
Mecid

現時点では可能ではないと思います。

私が持っている最良の提案は、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
  }
}
1
kgaidis

うわー!うーん、EditButton()を使用するかどうかはわかりません。

私はあなたがリストを持っていて、行をスワイプして削除する選択肢を右に表示したいと思いますか?

リストのクロージャの後に.onDelete(perform: delete)を実装するだけです。次に、クロージャーを処理する削除関数を定義する構造に関数を追加します。関数は次のように定義されることに注意してください:func delete (at offsets: IndexSet) {}

私が提案したものを追加して、関数本体が完了していなくてもコンパイルし(つまり、print()プレースホルダーを追加)、削除のスワイプ動作を確認できます。

1
Justin Ngan