Search code examples
swiftautolayoutconstraintsuistackview

What is wrong with this StackView?


what is wrong with my StackView? This is the code:

class PushUpViewController: UIViewController {

        override func viewDidLoad() {
            super.viewDidLoad()
            
            view.backgroundColor = .white
            setUpStackView()
        }
        
            func setUpStackView() {
            // SetUp StackView:
            stackView.translatesAutoresizingMaskIntoConstraints = false
            stackView.axis = .vertical
                stackView.alignment = .center
                stackView.distribution = .fillProportionally
            stackView.spacing = 50
            view.addSubview(stackView)
            
            // SetUp StackView Constraints:
                stackView.pin(to: view)
                stackView.setCustomSpacing(50, after: PushUpButton)
                stackView.setCustomSpacing(100, after: TimeLabel)
            
            // Set Elements to StackView:
            stackView.addArrangedSubview(TimeLabel)
            stackView.addArrangedSubview(PushUpButton)
            stackView.addArrangedSubview(secondStackView)
            

       // SetUp PushUpButton:
           PushUpButton.backgroundColor = .white
           PushUpButton.setTitle("\(count)", for: .normal)
           PushUpButton.setTitleColor(.systemGray, for: .normal)
           PushUpButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 70)
           
           
           PushUpButton.translatesAutoresizingMaskIntoConstraints = false
           
                PushUpButton.heightAnchor.constraint(equalToConstant: 300).isActive = true
                PushUpButton.widthAnchor.constraint(equalToConstant: 150).isActive = true
           
       
    // SetUp TimeLabel
           TimeLabel.textAlignment = .center
                   TimeLabel.text = "\(counter)"
                   TimeLabel.textColor = .black
                   TimeLabel.font = .boldSystemFont(ofSize: 30)
                   self.view.addSubview(TimeLabel)
                   
                   TimeLabel.translatesAutoresizingMaskIntoConstraints = false
                   
       
                TimeLabel.widthAnchor.constraint(equalToConstant: 300).isActive = true
                TimeLabel.heightAnchor.constraint(equalToConstant: 200).isActive = true
        
      
            
            
            // SetUp SecondStackView
            secondStackView.translatesAutoresizingMaskIntoConstraints = false
            secondStackView.axis = .horizontal
            secondStackView.alignment = .center
            secondStackView.distribution = .fillEqually
                secondStackView.spacing = 20
            
            
            // SetUp SecondStackView Constrains
                secondStackView.heightAnchor.constraint(equalToConstant: 50).isActive = true
                secondStackView.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -15).isActive = true
            
            
            // Set Elements:
            secondStackView.addArrangedSubview(breakButton)
            secondStackView.addArrangedSubview(stopbutton)
            
            //SetUp BreakButton
                  breakButton.backgroundColor = .lightGray
                  breakButton.setTitle("Break", for: .normal)
                  breakButton.setTitle("Start", for: .selected)
            breakButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20)
                  breakButton.setTitleColor(.white, for: .normal)
                  breakButton.layer.cornerRadius = 12
                  breakButton.layer.borderWidth = 1
                  breakButton.layer.borderColor = UIColor.white.cgColor
//               breakButton.addTarget(self, action: #selector(BreakButtonTapped), for: .touchUpInside)
                  
                  
                  breakButton.translatesAutoresizingMaskIntoConstraints = false
                  
               NSLayoutConstraint.activate([
                  breakButton.widthAnchor.constraint(equalToConstant: 150),
                  breakButton.heightAnchor.constraint(equalToConstant: 50)
               ])
              
                
               
              
              // SetUp StopButton:
                  stopbutton.backgroundColor = .systemRed
                  stopbutton.setTitle("Stop", for: .normal)
                  stopbutton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20)
                  stopbutton.setTitleColor(.white, for: .normal)
                  stopbutton.layer.cornerRadius = 12
                  stopbutton.layer.borderWidth = 1
                  stopbutton.layer.borderColor = UIColor.white.cgColor
//               stopbutton.addTarget(self, action: #selector(stopButtonTapped), for: .touchUpInside)
                  
                  
                  stopbutton.translatesAutoresizingMaskIntoConstraints = false
                  
               NSLayoutConstraint.activate([
                  stopbutton.widthAnchor.constraint(equalToConstant: 150),
                  stopbutton.heightAnchor.constraint(equalToConstant: 50)
                  ])
            
            
            }
    }
        
    
    
   

And this is how it look: enter image description here

But it should looks like this:

enter image description here

This is what comes in the console when I am on the StackView VC:

enter image description here

I have no idea what this means or what I should do to solve this problem

I do not understand StackViews... I watched a lot of yt tutorials but they are all the same and did't help me. My biggest problem is the distribution of the StackView: I don't know where the difference is


Solution

  • First tip: forget using .fillProportionally with stack views. It is almost never used ... and when it is used, it's used for very specific reasons.

    Second tip: during development, give your UI elements contrasting background colors to make it easy to see the frames at run-time.

    Third tip: Use leadingLowerCase for variable and function names... Use LeadingUpperCase for class names.

    Fourth tip: group similar code together - such as setting view properties, setting constraints, etc - and include logical comments to make it easier to follow what your code is doing.

    Take a look at this:

    class PushUpViewController: UIViewController {
        
        let stackView = UIStackView()
        let secondStackView = UIStackView()
        let pushUpButton = UIButton()
        let breakButton = UIButton()
        let stopbutton = UIButton()
        let timeLabel = UILabel()
        
        var count: Int = 0
        var counter: Float = 0.0
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            view.backgroundColor = .white
            setUpStackView()
        }
        
        func setUpStackView() {
            
            // SetUp StackView:
            stackView.translatesAutoresizingMaskIntoConstraints = false
            stackView.axis = .vertical
            stackView.alignment = .fill
            stackView.distribution = .fill
    
            // SetUp timeLabel
            timeLabel.textAlignment = .center
            timeLabel.text = "\(counter)"
            timeLabel.textColor = .black
            timeLabel.font = .boldSystemFont(ofSize: 30)
    
            // SetUp pushUpButton:
            pushUpButton.backgroundColor = .white
            pushUpButton.setTitle("\(count)", for: .normal)
            pushUpButton.setTitleColor(.systemGray, for: .normal)
            pushUpButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 70)
            
            // SetUp secondStackView
            secondStackView.axis = .horizontal
            secondStackView.alignment = .fill
            secondStackView.distribution = .fillEqually
            secondStackView.spacing = 20
            
            //SetUp breakButton
            breakButton.backgroundColor = .lightGray
            breakButton.setTitle("Break", for: .normal)
            breakButton.setTitle("Start", for: .selected)
            breakButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20)
            breakButton.setTitleColor(.white, for: .normal)
            breakButton.layer.cornerRadius = 12
            breakButton.layer.borderWidth = 1
            breakButton.layer.borderColor = UIColor.white.cgColor
            
            // SetUp stopButton:
            stopbutton.backgroundColor = .systemRed
            stopbutton.setTitle("Stop", for: .normal)
            stopbutton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20)
            stopbutton.setTitleColor(.white, for: .normal)
            stopbutton.layer.cornerRadius = 12
            stopbutton.layer.borderWidth = 1
            stopbutton.layer.borderColor = UIColor.white.cgColor
    
            // add buttons to horizontal second stack view
            secondStackView.addArrangedSubview(breakButton)
            secondStackView.addArrangedSubview(stopbutton)
    
            // if we want the center PushUpButton to be 300 x 150
            //  and centered vertically
            //  we need to embed it in a clear view
            let holderView = UIView()
            
            // add PushUpButton to holderView
            holderView.addSubview(pushUpButton)
    
            // views added as arrangedSubviews of a stack view automatically get
            //  .translatesAutoresizingMaskIntoConstraints = false
            // but, because we're adding the PushUpButton as a subview
            //  of holderView, we need to set it here
            pushUpButton.translatesAutoresizingMaskIntoConstraints = false
            
    
            // add views to stack view
            stackView.addArrangedSubview(timeLabel)
            stackView.addArrangedSubview(holderView)
            stackView.addArrangedSubview(secondStackView)
    
            // add stackView to view
            view.addSubview(stackView)
            
            // SetUp StackView Constraints:
            //stackView.pin(to: view)
            
            // respect safe-area
            let g = view.safeAreaLayoutGuide
            NSLayoutConstraint.activate([
                
                // constrain stackview to full view (safe-area)
                
                // to bottom with Zero extra space
                stackView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
    
                // to top with 20-pts "padding"
                stackView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
                
                // and 8-pts "padding" on each side
                stackView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
                stackView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
                
                // pushUpButton should be 300x150
                pushUpButton.widthAnchor.constraint(equalToConstant: 300.0),
                pushUpButton.heightAnchor.constraint(equalToConstant: 150.0),
                
                // pushUpButton should be centered in holderView
                pushUpButton.centerXAnchor.constraint(equalTo: holderView.centerXAnchor),
                pushUpButton.centerYAnchor.constraint(equalTo: holderView.centerYAnchor),
                
                // bottom buttons should have Height: 50
                secondStackView.heightAnchor.constraint(equalToConstant: 50.0),
                
            ])
    
            // break and stop button actions
            //breakButton.addTarget(self, action: #selector(BreakButtonTapped), for: .touchUpInside)
            //stopbutton.addTarget(self, action: #selector(stopButtonTapped), for: .touchUpInside)
    
            // during development, so we can see the layout easily
            //holderView.backgroundColor = .yellow
            //PushUpButton.backgroundColor = .green
            //TimeLabel.backgroundColor = .cyan
            
        }
    }
    

    Result on iPhone 11:

    enter image description here

    on iPhone 8:

    enter image description here

    and with background colors to help during development:

    enter image description here

    enter image description here

    Additional Tip:

    When learning auto layout (particularly stack views), work on your layout in Storyboard / Interface Builder. You can immediately see how it looks and what happens when changing values / properties. You can also change the View as: to immediately see how it looks on different devices / screen sizes. If you want to keep everything in code, once you have your layout looking the way you want, then replicate those constraints and settings in code.