Swiftui List Row Cells set padding after View appears

后端 未结 4 1540
醉梦人生
醉梦人生 2021-02-15 12:28

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

相关标签:
4条回答
  • 2021-02-15 12:57

    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

    0 讨论(0)
  • 2021-02-15 13:01

    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()
        }
    }
    
    0 讨论(0)
  • 2021-02-15 13:04
    List
    {
       ForEach(items)
       {(item) in
          NavigationLink(destination:Destination())
          {
           Text("example")
          }
       }
    }.listStyle(InsetListStyle())
    

    The .listStyle(InsetListStyle()) helped me to solve the problem in XCode12.

    0 讨论(0)
  • 2021-02-15 13:06

    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.

    0 讨论(0)
提交回复
热议问题