I have a standard List only with one Text and on the right side the arrow for navigation. But after the list is loading and appeared at Screen, the list addapt the cells I think
I've come up with a workaround to fix this issue. One caveat, while it fixes the shift in the table, it introduces a delay in Navigation Bar Title animation, so you are warned.
You can use UIKit's TableViewController in the meantime until Apple fixes SwiftUI's List object.
In summary, you need to create a TableViewController and wrap it in UIViewControllerRepresentable to then inject it into your SwiftUI view. Navigation action is best done through didSelectRowAt delegate method.
Update: seems like the issue has been resolved in the newest XCode 11.4 (however more issues are present in the simulator environment now)
I have a full code here: 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) -> UIViewController {
UIKitComboTableViewController(restaurants: restaurants)
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext) {
}
}
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()
}
}