【问题标题】:UIStackView not showingUIStackView 不显示
【发布时间】:2020-01-23 00:07:28
【问题描述】:

我正在尝试将 UIStackView 添加到我的窗口,但它没有显示。如下所示,我已经成功添加了一个 UINavigationBar。我还尝试添加各种其他控件,但实际上只显示了另一个 UIView。我已经附上了我的 ViewController 类:


class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {


    var pickerData: [String] = [String]()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        pickerData = ["Select a segment..."]

        let guide = view.safeAreaLayoutGuide
        let safeHeight = guide.layoutFrame.size.height
        let safeWidth = guide.layoutFrame.size.width

        let navBar = UINavigationBar(frame: CGRect(x: 0, y: safeHeight, width: 20, height: 44))

        self.view.addSubview(navBar)

        navBar.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0).isActive = true
        navBar.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0).isActive = true

        navBar.topAnchor.constraint(equalTo: guide.topAnchor, constant: 0).isActive = true

        navBar.translatesAutoresizingMaskIntoConstraints = false

        let navItem = UINavigationItem(title: "Add Binge Segment")
        let cancelItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.cancel, target: nil, action: #selector(cancel))
        navItem.leftBarButtonItem = cancelItem

        navBar.setItems([navItem], animated: false)


        var items:[UIView] = [UIView]()

        let picker = UIPickerView(frame: CGRect(x: safeWidth, y: navBar.frame.height + 50, width: 320, height: 230))
        picker.showsSelectionIndicator = true
        picker.delegate = self
        picker.dataSource = self

        items.append(picker)

        let stackView = UIStackView()
        stackView.axis = .vertical
        stackView.distribution = .fillProportionally
        stackView.alignment = .fill
        stackView.spacing = 10
        stackView.backgroundColor = .green
        stackView.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(stackView)

        stackView.topAnchor.constraint(equalTo: navBar.bottomAnchor, constant: 50).isActive = true
        stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 50).isActive = true

        stackView.trailingAnchor.constraint(equalTo: guide.trailingAnchor, constant: 0).isActive = true
        stackView.leadingAnchor.constraint(equalTo: guide.leadingAnchor, constant: 0).isActive = true

        stackView.addArrangedSubview(picker)


    }

    @objc func cancel() {

        print("Clicked")

    }

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 0
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return pickerData.count
    }

}


关于为什么这没有显示的任何想法?我看到的大多数答案都建议添加约束,但我已经有了它们

编辑:新视图控制器:


class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {


    var pickerData: [String] = [String]()

    var guide: UILayoutGuide = UILayoutGuide()
    var safeHeight: CGFloat = 0.0
    var safeWidth: CGFloat = 0.0

    var navBar: UINavigationBar = UINavigationBar()
    var stackView: UIStackView = UIStackView()

    var picker: UIPickerView = UIPickerView()

    var currentSelection: String = ""

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        pickerData = ["Select a segment..."]

        guide = view.safeAreaLayoutGuide
        safeHeight = guide.layoutFrame.size.height
        safeWidth = guide.layoutFrame.size.width

        navBar = UINavigationBar(frame: CGRect(x: 0, y: safeHeight, width: 20, height: 44))

        self.view.addSubview(navBar)

        picker = UIPickerView(frame: CGRect(x: safeWidth, y: navBar.frame.height + 50, width: 320, height: 230))

        self.view.addSubview(picker)

        stackView.axis = .vertical
        stackView.distribution = .fillProportionally
        stackView.alignment = .fill
        stackView.spacing = 10
        self.view.addSubview(stackView)




    }

    override func viewWillLayoutSubviews() {

        navBar.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0)
        navBar.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0)
        navBar.topAnchor.constraint(equalToSystemSpacingBelow: guide.topAnchor, multiplier: 0)

        navBar.translatesAutoresizingMaskIntoConstraints = false

        let navItem = UINavigationItem(title: "Add Binge Segment")
        let cancelItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.cancel, target: nil, action: #selector(cancel))
        navItem.leftBarButtonItem = cancelItem

        navBar.setItems([navItem], animated: false)


        var items:[UIView] = [UIView]()

        picker.showsSelectionIndicator = true
        picker.delegate = self
        picker.dataSource = self


        items.append(picker)

        stackView.translatesAutoresizingMaskIntoConstraints = false

        stackView.topAnchor.constraint(equalTo: navBar.bottomAnchor, constant: 50).isActive = true
        stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 50).isActive = true

        stackView.trailingAnchor.constraint(equalTo: guide.trailingAnchor, constant: 0).isActive = true
        stackView.leadingAnchor.constraint(equalTo: guide.leadingAnchor, constant: 0).isActive = true

        stackView.addArrangedSubview(picker)
    }

    @objc func cancel() {

        print("Clicked")

    }

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 0
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return pickerData.count
    }

    // The data to return fopr the row and component (column) that's being passed in
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return pickerData[row]
    }

    // Capture the picker view selection
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        // This method is triggered whenever the user makes a change to the picker selection.
        // The parameter named row and component represents what was selected.

        currentSelection = pickerData[row]
    }

【问题讨论】:

    标签: swift xcode uistackview


    【解决方案1】:

    首先,使用约束时无需指定框架。让自动布局引擎为您完成工作。

    其次,约束都可以在viewDidLoad()中设置——你不需要在viewWillLayoutSubviews()中设置任何东西。

    第三,不太清楚您希望选择器视图显示在哪里,或者为什么要将它放在堆栈视图中?我假设您希望选择器从导航栏底部下方 50 点处开始,并且您将向堆栈视图添加其他元素?

    所以,有几个提示:

    • 在开发过程中,为视图提供对比背景色,以便在运行时轻松查看帧
    • 使用Debug View Hierarchy 帮助找出错误/缺失的约束
    • 按逻辑关联对代码进行分组。如
      • 实例化对象
      • 设置对象属性
      • 添加子视图
      • 设置约束

    这是我得到的:

    对您的代码使用这些修改:

    class BenDentViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
    
        var pickerData: [String] = [String]()
    
        // instantiate navBar, stackView and picker
        var navBar: UINavigationBar = UINavigationBar()
        var stackView: UIStackView = UIStackView()
        var picker: UIPickerView = UIPickerView()
    
        var currentSelection: String = ""
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // sample picker data
            pickerData = [
                "Select a segment...",
                "Segment 1",
                "Segment 2",
                "Segment 3",
                "Segment 4",
            ]
    
            // set navBar properties
            let navItem = UINavigationItem(title: "Add Binge Segment")
            let cancelItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.cancel, target: self, action: #selector(cancel))
            navItem.leftBarButtonItem = cancelItem
            navBar.setItems([navItem], animated: false)
    
            // set picker properties
            picker.showsSelectionIndicator = true
            picker.delegate = self
            picker.dataSource = self
    
            // give it a background color so we can see its frame
            picker.backgroundColor = .yellow
    
            // set stackView properties
            stackView.axis = .vertical
            stackView.distribution = .fill
            stackView.alignment = .fill
            stackView.spacing = 10
    
            // add the picker to the stack view
            stackView.addArrangedSubview(picker)
    
            // add elements to self.view
            self.view.addSubview(navBar)
            self.view.addSubview(stackView)
    
            // we're using auto-layout constraints
            [navBar, stackView, picker].forEach {
                $0.translatesAutoresizingMaskIntoConstraints = false
            }
    
            let guide = view.safeAreaLayoutGuide
    
            NSLayoutConstraint.activate([
    
                // constrain navBar to top, leading, trailing and height of 44
                navBar.topAnchor.constraint(equalToSystemSpacingBelow: guide.topAnchor, multiplier: 0),
                navBar.leadingAnchor.constraint(equalTo: guide.leadingAnchor, constant: 0),
                navBar.trailingAnchor.constraint(equalTo: guide.trailingAnchor, constant: 0),
                navBar.heightAnchor.constraint(equalToConstant: 44.0),
    
                // constrain stackView leading and trailing
                stackView.trailingAnchor.constraint(equalTo: guide.trailingAnchor, constant: 0),
                stackView.leadingAnchor.constraint(equalTo: guide.leadingAnchor, constant: 0),
    
                // constrain stackView top: 50-pts from bottom of navBar
                stackView.topAnchor.constraint(equalTo: navBar.bottomAnchor, constant: 50),
    
                // not needed, depending on desired layout
                //stackView.bottomAnchor.constraint(equalTo: guide.bottomAnchor, constant: -50),
    
                ])
    
        }
    
        @objc func cancel() {
            print("Cancel Clicked")
        }
    
        func numberOfComponents(in pickerView: UIPickerView) -> Int {
            return 1
        }
    
        func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
            return pickerData.count
        }
    
        // The data to return fopr the row and component (column) that's being passed in
        func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
            return pickerData[row]
        }
    
        // Capture the picker view selection
        func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
            // This method is triggered whenever the user makes a change to the picker selection.
            // The parameter named row and component represents what was selected.
    
            currentSelection = pickerData[row]
    
            print("Selected row: \(row) value: \(pickerData[row])")
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      您需要将布局配置移动到viewWillLayoutSubviews,因为尚未正确设置视图框架

      这是一篇很好的文章,解释了视图控制器的生命周期

      https://medium.com/@felicity.johnson.mail/viewcontroller-lifestyle-e304e1078bc5

      【讨论】:

      • 嗨,我尝试实现我认为你建议的内容(请参阅帖子中的新视图控制器),但现在底部只显示了一个奇怪的东西(看起来像空的选择器视图)
      • 你需要调用 super.viewWillLayoutSubviews()
      猜你喜欢
      • 1970-01-01
      • 2016-08-22
      • 2018-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多