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
Edit: iOS 13.6 fixed the issue, my solution following from back then now produces a glitch instead of fixing it!
There is a potential fix for this which produces other complications:
Animations. This weird bug is affected by animations, so just give it an animation like
List {
ForEach(0..<book.chapters) { index in
NavigationLink(destination: ReadingView(book: self.book, chapter: index)){
Text("Kapitel \(index + 1)")
}
}
}.animation(.easeInOut(duration: 500))
.navigationBarTitle(Text(book.long_name), displayMode: .inline)
Will make the bug at least invisible, but be warned that all subviews will inherit that animation, so you manually need to override it again for them. If you are writing a professional app, rather use the TableView fix from Repose's answer.
Strange thing: We found out it happens on iPhone XR and 11 (Simulator and real device) but not on iPhone 11 Pro, so it might only occur on LCD devices???
I hope this helps future visitors of this thread who stumble on this thread like I did while experiencing that bug
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<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()
}
}
List
{
ForEach(items)
{(item) in
NavigationLink(destination:Destination())
{
Text("example")
}
}
}.listStyle(InsetListStyle())
The .listStyle(InsetListStyle())
helped me to solve the problem in XCode12.
I have the same issue but only on the simulator. When I’m running the app on any phone, no matter how old, it works perfectly fine as one would expect. You should try that.
Edit: ah now I see the mobile data, you are on your phone. In that case you can file a bug report to Apple and wait and always use newest software.