我想出了一个解决方法来解决这个问题。需要注意的是,虽然它修复了表格中的变化,但它会在导航栏标题动画中引入延迟,因此会警告您。
在 Apple 修复 SwiftUI 的 List 对象之前,您可以同时使用 UIKit 的 TableViewController。
总之,您需要创建一个 TableViewController 并将其包装在 UIViewControllerRepresentable 中,然后将其注入到您的 SwiftUI 视图中。导航操作最好通过 didSelectRowAt 委托方法完成。
更新:似乎问题已在最新的 XCode 11.4 中解决(但现在模拟器环境中存在更多问题)
我在这里有一个完整的代码:https ://gist.github.com/Rep0se/97d7a97cfd05f42aa597904e6a2cfd3d
//
// UIKitSwiftUITableView.swift
// Table Test
//
// Created on 2020-02-19.
// Note: While this solution fixes Table shifting bug, it introduces Navigation Bar Title bug for a Large Title. Beware.
// LBTATools can be downloaded using Swift Package Manager from: https://github.com/bhlvoong/LBTATools
//
import SwiftUI
import LBTATools
struct UIKitSwiftUITableView: View {
var body: some View {
NavigationView {
UIKitSwiftUIContainer()
}
}
}
struct Restaurante: Hashable {
let name: String
let image: String
}
struct UIKitSwiftUIContainer: View {
let restaurants = [
Restaurante(name: "Joe's Original", image: "house"),
Restaurante(name: "Pheasant Plucker", image: "house.fill"),
Restaurante(name: "Radius", image: "music.house"),
Restaurante(name: "The Ship", image: "music.house.fill")
]
var body: some View {
UIKitTableViewRepresentable(restaurants: restaurants)
.navigationBarTitle("Select a restaurant") // <- UI bug exests for Navigation Bar Title
.edgesIgnoringSafeArea(.all)
}
}
struct UIKitTableViewRepresentable: UIViewControllerRepresentable {
typealias UIViewControllerType = UIViewController
let restaurants: [Restaurante]
init(restaurants: [Restaurante]) {
self.restaurants = restaurants
}
func makeUIViewController(context: UIViewControllerRepresentableContext<UIKitTableViewRepresentable>) -> UIViewController {
UIKitComboTableViewController(restaurants: restaurants)
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<UIKitTableViewRepresentable>) {
}
}
class UIKitComboTableViewController: UITableViewController {
let reuseIdentifier = "reuseIdentifier"
var restaurants: [Restaurante]
init(restaurants: [Restaurante]) {
self.restaurants = restaurants
super.init(style: .insetGrouped)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(TableCell.self, forCellReuseIdentifier: reuseIdentifier)
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return restaurants.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath) as? TableCell {
cell.viewModel.name = restaurants[indexPath.row].name
cell.viewModel.image = restaurants[indexPath.row].image
cell.accessoryType = .disclosureIndicator
return cell
} else {
return UITableViewCell()
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let hostingController = UIHostingController(rootView: UIKitSwiftUIContainer())
show(hostingController, sender: self)
}
}
class TableCell: UITableViewCell {
let viewModel = RestaurantViewModel()
lazy var row = ListRowView(viewModel: viewModel)
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let hostingController = UIHostingController(rootView: row)
addSubview(hostingController.view)
hostingController.view.fillSuperview()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
struct ListRowView: View {
@ObservedObject var viewModel: RestaurantViewModel
var body: some View {
HStack{
Image("Avatar").renderingMode(.original).padding()
Text(viewModel.name)
.foregroundColor(.black)
Spacer()
}.frame(minHeight: 44)
}
}
class RestaurantViewModel: ObservableObject {
@Published var name = ""
@Published var image = ""
}
struct UIKitSwiftUITableView_Previews: PreviewProvider {
static var previews: some View {
UIKitSwiftUITableView()
}
}