Skip to content

Instantly share code, notes, and snippets.

@yosshi4486
Last active July 18, 2023 13:55
Show Gist options
  • Save yosshi4486/abf43e429e5cfe3c7c2c1ecdb613e0f8 to your computer and use it in GitHub Desktop.
Save yosshi4486/abf43e429e5cfe3c7c2c1ecdb613e0f8 to your computer and use it in GitHub Desktop.
UIKitTableView for some cases SwiftUI.List couldn't be applied.
//
// UIKitTableView.swift
//
// Created by yosshi4486 on 2023/07/18.
//
import SwiftUI
private struct MoveActionEnvironmentKey: EnvironmentKey {
typealias Value = ((Int, Int) -> ())?
static var defaultValue: Value = nil
}
private struct DeleteActionEnvironmentKey: EnvironmentKey {
typealias Value = ((Int) -> ())?
static var defaultValue: Value = nil
}
private extension EnvironmentValues {
var onMoveAction: ((Int, Int) -> ())? {
get {
return self[MoveActionEnvironmentKey.self]
}
set {
self[MoveActionEnvironmentKey.self] = newValue
}
}
var onDeleteAction: ((Int) -> ())? {
get {
return self[DeleteActionEnvironmentKey.self]
}
set {
self[DeleteActionEnvironmentKey.self] = newValue
}
}
}
struct UIKitTableView<Data, RowContent> : UIViewRepresentable where Data : RandomAccessCollection, Data.Element: Identifiable, Data.Index == Int, RowContent : View {
typealias UIViewType = UITableView
var style: UITableView.Style
@Binding var data: Data
@Binding var selection: Data.Element?
private var rowContent: (Data.Element) -> RowContent
@Environment(\.editMode) var editMode
@Environment(\.onMoveAction) private var onMoveAction
@Environment(\.onDeleteAction) private var onDeleteAction
init(
_ data: Binding<Data>,
selection: Binding<Data.Element?>,
style: UITableView.Style = .insetGrouped,
@ViewBuilder rowContent: @escaping (Data.Element) -> RowContent
) {
self._data = data
self._selection = selection
self.style = style
self.rowContent = rowContent
}
func makeUIView(context: Context) -> UITableView {
let tableView = UITableView(frame: .zero, style: style)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.delegate = context.coordinator
tableView.dataSource = context.coordinator
return tableView
}
func updateUIView(_ uiView: UITableView, context: Context) {
uiView.setEditing(editMode?.wrappedValue == .active, animated: true)
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate {
var owner: UIKitTableView<Data, RowContent>
init(_ owner: UIKitTableView<Data, RowContent>) {
self.owner = owner
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return owner.data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let element = owner.data[indexPath.row]
let rowContent = owner.rowContent(element)
cell.contentConfiguration = UIHostingConfiguration { rowContent.id(element.id) }
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
owner.selection = owner.data[indexPath.row]
}
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return tableView.isEditing
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
owner.onMoveAction?(sourceIndexPath.row, destinationIndexPath.row)
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
owner.onDeleteAction?(indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
}
}
extension View {
func onMove(_ action: @escaping (Int, Int) -> ()) -> some View {
self.environment(\.onMoveAction, action)
}
func onDelete(_ action: @escaping (Int) -> ()) -> some View {
self.environment(\.onDeleteAction, action)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment