【问题标题】:Swift: UIStackView Overlapping all Views instead of Stacking them VerticallySwift:UIStackView 重叠所有视图而不是垂直堆叠它们
【发布时间】:2021-01-26 06:04:33
【问题描述】:

我正在尝试为我的应用创建一个统计页面,该页面将根据用户拥有的数据类型动态创建各种图表。为此,我根据本教程堆叠了多个 ViewController:https://swiftwithmajid.com/2019/02/27/building-complex-screens-with-child-viewcontrollers/

我遇到了这样一个问题,即 ViewController 的视图作为排列的子视图添加到主 StackView 中,但它不是垂直堆叠视图并允许我滚动浏览它们,而是将它们堆叠在一起z 方向。

这里是 StackViewController 代码:

class StackViewController: UIViewController {
    private let scrollView = UIScrollView()
    private let stackView = UIStackView()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(scrollView)
        scrollView.addSubview(stackView)
        setupConstraints()
        stackView.axis = .vertical
    }

    private func setupConstraints() {
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        stackView.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([
                    scrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
                    scrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
                    scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
                    scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
            stackView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
                    stackView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
                    stackView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
                    stackView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
            stackView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor)
                    ])
    }
}

extension StackViewController {
    func add(_ child: UIViewController) {
        addChild(child)
        stackView.addArrangedSubview(child.view)
        print(child.view!)
        child.didMove(toParent: self)
    }

    func remove(_ child: UIViewController) {
        guard child.parent != nil else {
            return
        }

        child.willMove(toParent: nil)
        stackView.removeArrangedSubview(child.view)
        child.view.removeFromSuperview()
        child.removeFromParent()
    }
}

这里是我创建每个视图控制器并将其添加到 StackViewController 的地方。 现在,我运行一个循环并一遍又一遍地添加单个视图控制器的副本:

class PrototypeViewController: StackViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        for _ in 0...10 {
            setupUI()
        }
    }

    private func setupUI() {
        let storyboard = UIStoryboard(name: "ConsistencyGraph", bundle: .main)
        let consistencyGraphVC = storyboard.instantiateViewController(identifier: "ConsistencyGraphVC") as! ConsistencyGraphVC
        add(consistencyGraphVC)
        consistencyGraphVC.setupUI(name: "sessionName", consistencyPercentage: 30, ballsHit: 10)
    }
}

这是视图控制器代码:

class ConsistencyGraphVC: UIViewController {

    @IBOutlet weak var mainView: UIView!
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var ballsHitLabel: UILabel!
    @IBOutlet weak var pieChartView: PieChartView!
        
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    open func setupUI(name: String, consistencyPercentage: Double, ballsHit: Int) {
        displayName(name:name)
        drawPieChart(consistencyPercentage: consistencyPercentage)
        displayBallsHit(ballsHit: ballsHit)
    }
    
    private func displayName(name: String) {
        let prefix = "Consistency: "
        let title = prefix + name
        titleLabel.text = title
    }
    
    private func displayBallsHit(ballsHit: Int) {
        ballsHitLabel.text = String(ballsHit)
    }
    
    private func drawPieChart(consistencyPercentage: Double) {
        let maxPercent:Double = 100
        let remainingPercent = maxPercent - consistencyPercentage
        let dataEntry = [PieChartDataEntry(value: consistencyPercentage, data: String(consistencyPercentage)), PieChartDataEntry(value: remainingPercent, data: nil)]
        let dataSet = PieChartDataSet(entries: dataEntry)
        let chartData = PieChartData(dataSet: dataSet)
        let color1 = randomColor()
        let color2 = randomColor()
        dataSet.colors = [color1, color2]
        pieChartView.data = chartData
    }
    
    private func randomColor() -> UIColor {
        let red = Double(arc4random_uniform(256))
        let green = Double(arc4random_uniform(256))
        let blue = Double(arc4random_uniform(256))
        let color = UIColor(red: CGFloat(red/255), green: CGFloat(green/255), blue: CGFloat(blue/255), alpha: 1)
        return color
    }
}

起初,我认为这是因为 View Controller 的大小可能不明确。然后我硬编码了每个视图控制器的宽度和高度,但仍然没有运气。

非常感谢任何和所有帮助!我不知道这怎么可能。

提前谢谢你!

【问题讨论】:

    标签: ios swift uiviewcontroller uiscrollview uistackview


    【解决方案1】:

    我终于找到了解决办法!

    我需要补充:

    child.view.heightAnchor.constraint(equalToConstant: child.view.frame.size.height).isActive = true
    

    到这里的 StackViewController:

    func add(_ child: UIViewController) {
            addChild(child)
            child.view.heightAnchor.constraint(equalToConstant: child.view.frame.size.height).isActive = true
            stackView.addArrangedSubview(child.view)
            child.didMove(toParent: self)
        }
    

    我不知道为什么会这样。我已经硬编码了视图的高度,但是 stackView 还希望我在添加视图之前对其进行约束。

    我希望这对将来的人有所帮助!我一直在用头撞墙......

    【讨论】:

    • 解释为什么...当您使用.instantiateViewController() 加载VC 时,该控制器的“根”视图具有.translatesAutoresizingMaskIntoConstraints = true。但是,当您这样做时:stackView.addArrangedSubview(child.view),堆栈视图会自动设置child.view.translatesAutoresizingMaskIntoConstraints = false。如果您的子视图是方形的(1:1 比例),您可以将该行更改为:child.view.heightAnchor.constraint(equalTo: child.view.widthAnchor).isActive = true
    • 非常感谢@DonMag 的解释!总是更好地了解某些东西为什么有效,以便我将来可以使用它。
    【解决方案2】:

    您在 ScrollView 中忘记了 StackView 所需的一些约束。 你只有trailing, top, and bottom 这还不够。

    • 正确的一个:
    stackView.leadingAnchor
    stackView.trailingAnchor
    stackView.topAnchor
    stackView.bottomAnchor
    stackView.widthAnchor
    

    【讨论】:

    • 你说的是 StackViewController 吗?如果是这样,我有“stackView.leadingAnchor.constraint(equalTo:scrollView.contentLayoutGuide.leadingAnchor),stackView.trailingAnchor.constraint(equalTo:scrollView.contentLayoutGuide.trailingAnchor),stackView.topAnchor.constraint(equalTo:scrollView.contentLayoutGuide.topAnchor), stackView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor), stackView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor)"
    • 我应该在其他地方更改约束吗?
    • 但是你展示的代码不存在那些约束?您只需为 stackView 添加 3 个约束
    • 所有约束,包括您提到的约束,都在上面 StackViewController 类的 setupConstraints() 函数中。还有其他地方我应该设置 StackView 约束吗?
    猜你喜欢
    • 2019-04-04
    • 2015-05-16
    • 2018-05-11
    • 1970-01-01
    • 1970-01-01
    • 2016-08-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多