如何修复 UITableView 不显示在 UIStackView 中

How to fix UITableView not displaying in UIStackView

我按照教程以编程方式(没有故事板)构建了一个显示当前城市和温度的天气应用程序。我正在通过添加 UITableView 修改它以显示 5 天的预报,而不仅仅是当前温度,但它没有显示。

这是我的 WeatherView 代码:

class WeatherView: UIView, UITableViewDelegate, UITableViewDataSource {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func setup() {
        setupViews()
        setupConstraints()
    }

    private func setupViews() {
        self.addSubview(mainStack)
        conditionsImageStack.addArrangedSubview(conditionsImageView)
        mainStack.addArrangedSubview(conditionsImageStack)


//        forecastTable.register(UITableView.self, forCellReuseIdentifier: "forecast")
        forecastTable.register(UITableViewCell.self, forCellReuseIdentifier: "forecast")
        forecastTable.delegate = self
        forecastTable.dataSource = self

        mainStack.addArrangedSubview(centerContentStack)
//        centerContentStack.addArrangedSubview(temperatureLabel)
        centerContentStack.addArrangedSubview(forecastTable)
        centerContentStack.addArrangedSubview(cityAndConditionsStack)

        cityAndConditionsStack.addArrangedSubview(cityLabel)
        cityAndConditionsStack.addArrangedSubview(conditionsLabel)

        mainStack.addArrangedSubview(buttonsStack)
        buttonsStack.addArrangedSubview(celsiusButton)
        buttonsStack.addArrangedSubview(fahrenheitButton)
        buttonsStack.addArrangedSubview(UIView(frame: .zero))
    }

    private func setupConstraints() {
        mainStack.pinEdges(to: self)
    }

    let mainStack: UIStackView = {
        let stackView = UIStackView(frame: .zero)
        stackView.axis = .vertical
        stackView.distribution = .equalSpacing
        stackView.spacing = 10
        stackView.isLayoutMarginsRelativeArrangement = true
        stackView.layoutMargins = UIEdgeInsets(top: 10, left: 30, bottom: 30, right: 30)
        return stackView
    }()

    let conditionsImageStack: UIStackView = {
        let stackView = UIStackView(frame: .zero)
        stackView.axis = .vertical
        stackView.distribution = .equalSpacing
        stackView.alignment = .trailing
        stackView.spacing = 10
        return stackView
    }()

    let cityAndConditionsStack: UIStackView = {
        let stackView = UIStackView(frame: .zero)
        stackView.axis = .vertical
        stackView.distribution = .fillProportionally
        stackView.spacing = 10
        return stackView
    }()

    let centerContentStack: UIStackView = {
        let stackView = UIStackView(frame: .zero)
        stackView.axis = .vertical
        stackView.distribution = .fillProportionally
        stackView.alignment = .center
        stackView.spacing = 60
        return stackView
    }()

    // TABLE CODE HERE

    var animalArray : [String] = ["elephant", "pig", "goat"]

    var forecastTable: UITableView = {
        let tableView = UITableView()
        let estimatedHeight = tableView.numberOfRows(inSection: 3) //You may need to modify as necessary
//        let width = parentView.frame.size.width
        let width = estimatedHeight
        tableView.frame = CGRect(x: 0, y: 0, width: width, height: estimatedHeight)

        return tableView
    }()

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 3
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = forecastTable.dequeueReusableCell(withIdentifier: "forecast")
        cell?.textLabel!.text = "Success"
        return cell!
    }

    let temperatureLabel: UILabel = {
        let label = UILabel(frame: .zero)
        label.font = UIFont.systemFont(ofSize: 144)
        label.textColor = .white
        label.textAlignment = .center
        label.text = "18°"
        return label
    }()

    let cityLabel: UILabel = {
        let label = UILabel(frame: .zero)
        label.font = UIFont.systemFont(ofSize: 36)
        label.textColor = .white
        label.textAlignment = .center
        label.text = "Atlanta"
        return label
    }()

    let conditionsLabel: UILabel = {
        let label = UILabel(frame: .zero)
        label.font = UIFont.systemFont(ofSize: 20)
        label.textColor = .white
        label.textAlignment = .center
        label.text = "Sunny"
        return label
    }()

    let conditionsImageView: UIImageView = {
        let image = UIImage(named: "sun")
        let imageView = UIImageView(image: image)
        imageView.contentMode = .scaleAspectFit
        imageView.widthAnchor.constraint(equalToConstant: image!.size.width).isActive = true
        imageView.heightAnchor.constraint(equalToConstant: image!.size.height).isActive = true
        return imageView
    }()

    let celsiusButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("°C", for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 73)
        button.setTitleColor(.white, for: .normal)
        return button
    }()

    let fahrenheitButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("°F", for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 73)
        button.setTitleColor(.white, for: .normal)
        return button
    }()

    let buttonsStack: UIStackView = {
        let stackView = UIStackView(frame: .zero)
        stackView.axis = .horizontal
        stackView.distribution = .equalCentering
        stackView.spacing = 10
        return stackView
    }()
}

这是我的 ViewController 代码:

class WeatherViewController: UIViewController {
    var mainView: WeatherView! { return self.view as! WeatherView }
    let presenter: WeatherPresenter!

    init(with presenter: WeatherPresenter){
        self.presenter = presenter
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init coder not implemented")
    }


    override func viewDidLoad() {
        super.viewDidLoad()
        updateBackground()
    }

    func updateBackground() {
        self.mainView.updateGradient(presenter.backgroundColor)
    }

    override func loadView() {
        self.view = WeatherView(frame: UIScreen.main.bounds)
    }
}

这是我的 UIView + 约束代码:

extension UIView {
    func pinEdges(to view: UIView){
        self.translatesAutoresizingMaskIntoConstraints = false
        self.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
        self.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        self.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        self.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    }
}

我曾尝试通过 tableView.frame = CGRect(x: 0, y: 0, width: width, height: estimatedHeight) 设置尺寸来强制它显示,但这没有用。

我在视图 class 中注册 table 而不是视图控制器 class,但我不确定这是否是问题所在或如何正确修改它.

您正在将 mainStack 添加到 superView 但未指定其尺寸。您需要像这样对 mainStack 设置约束,

mainStack.translatesAutoresizingMaskIntoConstraints = false
mainStack.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
mainStack.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
mainStack.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
mainStack.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true

以上代码用mainStack填充了整个超级视图。您可以根据需要修改此代码。

你做错了几件事...

首先,在您的 var forecastTable: UITableView = {...} 声明中,您有一行:

let estimatedHeight = tableView.numberOfRows(inSection: 3)

但是,在那一点上,table 视图没有 dataSource——即使有,您的数据源也只有 section. So the value returned is undefined. If Iprint(esttmatedHeight)I get 9223372036854775807. So you are trying to set the frame of your table view to9223372036854775807 x 9223372036854775807`

接下来,当您将 table 视图添加到堆栈视图时,堆栈视图将尝试根据堆栈视图的属性和 table 视图的固有大小对其进行排列。但是,table 视图此时没有固有大小 - 您 必须 使用自动布局属性。

因此,删除 table 视图的框架设置,并将其添加到堆栈视图后,使用:

    // I'm guessing you want a height based on number of rows * row height?
    // so, something like:
    let estimatedHeight = CGFloat(3 * 44)

    forecastTable.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        forecastTable.widthAnchor.constraint(equalTo: centerContentStack.widthAnchor),
        forecastTable.heightAnchor.constraint(equalToConstant: estimatedHeight),
        ])

这将使 table 视图与容纳它的 centerContentStack 具有相同的宽度,并为其指定一个高度。

此时,您应该会看到您的 table。