Swiftui List Row Cells set padding after View appears

后端 未结 4 1555
醉梦人生
醉梦人生 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 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) -> 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()
        }
    }
    

提交回复
热议问题