Home > Net >  Why my 2D UIViews don't appear on screen?
Why my 2D UIViews don't appear on screen?

Time:10-13

I'm trying to make UIView that contains 12x7 UIViews with margins. I thought that the best way gonna be make 7 Vertical Stacks and then add all them on one big Horizontal stack. And I coded it, but problem is that this Horizontal Stacks doesn't appear on the screen at all (I've tried Xcode feature to see layers there is nothing).

This is my code:

import UIKit

class CalendarView: UIView {

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

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        setupView()
    }

    private func setupView() {
        // array to add in future in columnsStackView
        var columnStacks: [UIStackView] = []

        for columns in 1...12 {
            // array to add in future in columnStackView
            var columnViews: [UIView] = []

            for cell in 1...7 {
                let cellView = UIView(frame: CGRect(x: 0, y: 0, width: 24, height: 24))
                cellView.backgroundColor = .orange
                columnViews.append(cellView)
            }

            // create columnStackView and add all 7 views
            let columnStackView = UIStackView(arrangedSubviews: columnViews)
            columnStackView.axis = .vertical
            columnStackView.distribution = .fillEqually
            columnStackView.alignment = .fill
            columnStackView.spacing = 4

            columnStacks.append(columnStackView)
        }

        // create columnsStackView and add those 12 stacks
        let columnsStackView = UIStackView(arrangedSubviews: columnStacks)
        columnsStackView.axis = .horizontal
        columnsStackView.distribution = .fillEqually
        columnsStackView.alignment = .fill
        columnsStackView.spacing = 4
        columnsStackView.translatesAutoresizingMaskIntoConstraints = false

        self.addSubview(columnsStackView)
    }
}

Can you please help me with that!!!

CodePudding user response:

Couple things...

A UIStackView uses auto-layout when arranging its subviews, so this line:

let cellView = UIView(frame: CGRect(x: 0, y: 0, width: 24, height: 24))

will create a UIView, but the width and height will be ignored.

You need to set those with constraints:

for cell in 1...7 {
    let cellView = UIView()
    cellView.backgroundColor = .orange
                
    // we want each "cellView" to be 24x24 points
    cellView.widthAnchor.constraint(equalToConstant: 24.0).isActive = true
    cellView.heightAnchor.constraint(equalTo: cellView.widthAnchor).isActive = true
                
    columnViews.append(cellView)
}

Now, because we've explicitly set the width and height of the "cellViews" we can set the stack view .distribution = .fill (instead of .fillEqually).

Next, we have to constrain the "outer" stack view (columnsStackView) to the view itself:

// constrain the "outer" stack view to self
NSLayoutConstraint.activate([
    columnsStackView.topAnchor.constraint(equalTo: topAnchor),
    columnsStackView.leadingAnchor.constraint(equalTo: leadingAnchor),
    columnsStackView.trailingAnchor.constraint(equalTo: trailingAnchor),
    columnsStackView.bottomAnchor.constraint(equalTo: bottomAnchor),
])

otherwise, the view will have 0x0 dimensions.

Here is a modified version of your class:

class CalendarView: UIView {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        setupView()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        setupView()
    }
    
    private func setupView() {
        // array to add in future in columnsStackView
        var columnStacks: [UIStackView] = []
        
        for columns in 1...12 {
            // array to add in future in columnStackView
            var columnViews: [UIView] = []
            
            for cell in 1...7 {
                let cellView = UIView()
                cellView.backgroundColor = .orange
                
                // we want each "cellView" to be 24x24 points
                cellView.widthAnchor.constraint(equalToConstant: 24.0).isActive = true
                cellView.heightAnchor.constraint(equalTo: cellView.widthAnchor).isActive = true
                
                columnViews.append(cellView)
            }
            
            // create columnStackView and add all 7 views
            let columnStackView = UIStackView(arrangedSubviews: columnViews)
            columnStackView.axis = .vertical
            columnStackView.distribution = .fill
            columnStackView.alignment = .fill
            columnStackView.spacing = 4
            
            columnStacks.append(columnStackView)
        }
        
        // create columnsStackView and add those 12 stacks
        let columnsStackView = UIStackView(arrangedSubviews: columnStacks)
        columnsStackView.axis = .horizontal
        columnsStackView.distribution = .fill
        columnsStackView.alignment = .fill
        columnsStackView.spacing = 4
        columnsStackView.translatesAutoresizingMaskIntoConstraints = false
        
        self.addSubview(columnsStackView)
        
        // constrain the "outer" stack view to self
        NSLayoutConstraint.activate([
            columnsStackView.topAnchor.constraint(equalTo: topAnchor),
            columnsStackView.leadingAnchor.constraint(equalTo: leadingAnchor),
            columnsStackView.trailingAnchor.constraint(equalTo: trailingAnchor),
            columnsStackView.bottomAnchor.constraint(equalTo: bottomAnchor),
        ])
    }
}

and a simple test controller to show how it can be used:

class CalendarTestViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let cv = CalendarView()
        
        cv.translatesAutoresizingMaskIntoConstraints = false
        
        view.addSubview(cv)
        
        // the CalendarView will size itself, so we only need to
        //  provide x and y position constraints
        NSLayoutConstraint.activate([
            cv.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            cv.centerYAnchor.constraint(equalTo: view.centerYAnchor),
        ])
        
        // let's give it a background color so we can see its frame
        cv.backgroundColor = .systemYellow
    }

}

the result:

enter image description here

  • Related