Last active
July 18, 2023 13:55
-
-
Save yosshi4486/abf43e429e5cfe3c7c2c1ecdb613e0f8 to your computer and use it in GitHub Desktop.
UIKitTableView for some cases SwiftUI.List couldn't be applied.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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