gii
gii

Reputation: 11

Incorrect display of elements in UIScrollView

I use the scroll on the screen. At the same time, when displaying the screen on SE there are no problems, when displaying on large screens, a large gap appears between two elements. How to change this problem? I change constraints, but don't have results

import UIKit

class PlayInfoViewController: UIViewController {
    private let mainScrollView: UIScrollView = {
        let sv = UIScrollView()
        sv.backgroundColor = UIColor(named: "backgroundColor")
        sv.translatesAutoresizingMaskIntoConstraints = false
        return sv
    }()
    
    private let contentView: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(named: "backgroundColor")
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    private let horisontalStackViews: [UIStackView] = {
        var stackViews: [UIStackView] = []
        let textsForMainLabel = [
            "Draw a grid with three rows and three columns, creating nine squares in total.",
            "Players take turns placing their marker (X or O) in an empty square. To make a move, a player selects a number corresponding to the square where they want to place their marker.",
            "Player X starts by choosing a square (e.g., square 5). Player O follows by choosing an empty square (e.g., square 1). Continue alternating turns until the game ends.",
            "The first player to align three of their markers horizontally, vertically, or diagonally wins. Examples of Winning Combinations: Horizontal: Squares 1, 2, 3 or 4, 5, 6 or 7, 8, 9 Vertical: Squares 1, 4, 7 or 2, 5, 8 or 3, 6, 9 Diagonal: Squares 1, 5, 9 or 3, 5, 7"
        ]
        
        var number = 1
        for text in textsForMainLabel {
            let hStackView = UIStackView(
                arrangedSubviews: [
                    RoundView(
                        frame: CGRect.zero,
                        numberOfPosition: number
                    ),
                    RectangleView(
                        frame: CGRect.zero,
                        textForMainLabel: text
                    )
                ],
                axis: .horizontal,
                spacing: 20,
                alignment: .top)
            
            stackViews.append(hStackView)
            number += 1
        }
        
        return stackViews
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor(named: "backgroundColor")
       
        setupViews()
        setConstraints()
    }
    
    private func setupViews() {
        view.addSubview(mainScrollView)
        mainScrollView.addSubview(contentView)
        
        view.addSubview(horisontalStackViews[0])
        view.addSubview(horisontalStackViews[1])
        view.addSubview(horisontalStackViews[2])
        view.addSubview(horisontalStackViews[3])
        
        horisontalStackViews[0].translatesAutoresizingMaskIntoConstraints = false
        horisontalStackViews[1].translatesAutoresizingMaskIntoConstraints = false
        horisontalStackViews[2].translatesAutoresizingMaskIntoConstraints = false
        horisontalStackViews[3].translatesAutoresizingMaskIntoConstraints = false
        
        let hConst = contentView.heightAnchor.constraint(equalTo: mainScrollView.heightAnchor)
        hConst.isActive = true
        hConst.priority = UILayoutPriority(500)
    }
}

extension PlayInfoViewController {
    private func setConstraints() {
        NSLayoutConstraint.activate([
            mainScrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            mainScrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 42),
            mainScrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            mainScrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
       
            contentView.leadingAnchor.constraint(equalTo: mainScrollView.leadingAnchor),
            contentView.topAnchor.constraint(equalTo: mainScrollView.topAnchor),
            contentView.trailingAnchor.constraint(equalTo: mainScrollView.trailingAnchor),
            contentView.bottomAnchor.constraint(equalTo: mainScrollView.bottomAnchor),
            contentView.widthAnchor.constraint(equalTo: mainScrollView.widthAnchor),
            //            contentView.heightAnchor.constraint(equalTo: mainScrollView.heightAnchor, multiplier: 2),
  
            horisontalStackViews[0].leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 21),
            horisontalStackViews[0].topAnchor.constraint(equalTo: contentView.topAnchor),
            horisontalStackViews[0].trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -21),
            //            horisontalStackViews[0].widthAnchor.constraint(equalTo: contentView.widthAnchor),
            //            horisontalStackViews[0].heightAnchor.constraint(equalToConstant: 75)
     
            horisontalStackViews[1].leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 21),
            horisontalStackViews[1].topAnchor.constraint(equalTo: horisontalStackViews[0].bottomAnchor, constant: 10),
            horisontalStackViews[1].trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -21),
            //            horisontalStackViews[1].widthAnchor.constraint(equalTo: contentView.widthAnchor),
            //            horisontalStackViews[1].heightAnchor.constraint(equalToConstant: 192)

            horisontalStackViews[2].leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 21),
            horisontalStackViews[2].topAnchor.constraint(equalTo: horisontalStackViews[1].bottomAnchor, constant: 10),
            horisontalStackViews[2].trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -21),
            //            horisontalStackViews[2].widthAnchor.constraint(equalTo: contentView.widthAnchor),
            //            horisontalStackViews[2].heightAnchor.constraint(equalToConstant: 171)

            horisontalStackViews[3].leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 21),
            horisontalStackViews[3].topAnchor.constraint(equalTo: horisontalStackViews[2].bottomAnchor, constant: 10),
            horisontalStackViews[3].trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -21),
            horisontalStackViews[3].bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
            //            horisontalStackViews[3].widthAnchor.constraint(equalTo: contentView.widthAnchor),
            //            horisontalStackViews[3].heightAnchor.constraint(equalToConstant: 255)
        ])
    }
}

I change constraint and hConst. Don't have result

 horisontalStackViews[3].bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
let hConst = contentView.heightAnchor.constraint(equalTo: mainScrollView.heightAnchor)
        hConst.isActive = true
        hConst.priority = UILayoutPriority(500)

class RoundView: UIView {
    var numberOfPosition: Int
    
    lazy var numberLabel: UILabel = {
        let label = UILabel()
        label.text = "Some text"
        label.font = UIFont.systemFont(ofSize: 20, weight: .regular)
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    required init(frame: CGRect, numberOfPosition: Int) {
        self.numberOfPosition = numberOfPosition
        super.init(frame: frame)
        
        layer.cornerRadius = 22.5
        translatesAutoresizingMaskIntoConstraints = false
        
        numberLabel.text = String(numberOfPosition)
        
        setupView()
        setConstraints()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupView() {
        backgroundColor = #colorLiteral(red: 0.8375778794, green: 0.7538908124, blue: 0.96424371, alpha: 1)
        
        addSubview(numberLabel)
    }
}

extension RoundView {
    private func setConstraints() {
        NSLayoutConstraint.activate([
            numberLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 18),
            numberLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -18),
            numberLabel.topAnchor.constraint(equalTo: topAnchor, constant: 12),
            numberLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -12)
        ])
    }
}

class RectangleView: UIView {
    var textForMainLabel: String
    
    lazy var mainLabel: UILabel = {
        let label = UILabel()
        label.text = "Some text"
        label.font = UIFont.systemFont(ofSize: 18, weight: .regular)
        label.numberOfLines = 0
        label.minimumScaleFactor = 0.5
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    required init(frame: CGRect, textForMainLabel: String) {
        self.textForMainLabel = textForMainLabel
        super.init(frame: frame)
        
        layer.cornerRadius = 30
        translatesAutoresizingMaskIntoConstraints = false
        
        mainLabel.text = textForMainLabel
        
        setupView()
        setConstraints()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupView() {
        backgroundColor = #colorLiteral(red: 0.8718322515, green: 0.8867664933, blue: 0.9465543628, alpha: 1)
        
        addSubview(mainLabel)
    }
}

extension RectangleView {
    private func setConstraints() {
        NSLayoutConstraint.activate([
            mainLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 24),
            mainLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -24),
            mainLabel.topAnchor.constraint(equalTo: topAnchor, constant: 12),
            mainLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -12)
        ])
    }
}

It's Good enter image description here

This is a wrong

enter image description here

Upvotes: -1

Views: 77

Answers (1)

DonMag
DonMag

Reputation: 77672

Instead of constraining your horizontal stack view "rows," let's add them to a Vertical stack view.

To avoid the "gap" between the 1st and 2nd "row" on the larger screens, we do not set a height constraint on either the vertical stack view or the "content" view. On small screens - such as the SE - we get scrolling. On larger screens, we get a bit of space at the bottom, while keeping the "row spacing" consistent.

Looks like this:

Result


RoundView

class RoundView: UIView {
    var numberOfPosition: Int
    
    lazy var numberLabel: UILabel = {
        let label = UILabel()
        label.textAlignment = .center
        label.text = "0"
        label.font = UIFont.systemFont(ofSize: 20, weight: .regular)
        label.translatesAutoresizingMaskIntoConstraints = false
        
        // make sure the label frame cannot compress
        label.setContentCompressionResistancePriority(.required, for: .horizontal)
        label.setContentCompressionResistancePriority(.required, for: .vertical)
        
        return label
    }()
    
    required init(frame: CGRect, numberOfPosition: Int) {
        self.numberOfPosition = numberOfPosition
        super.init(frame: frame)
        
        translatesAutoresizingMaskIntoConstraints = false
        
        numberLabel.text = String(numberOfPosition)
        
        setupView()
        setConstraints()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupView() {
        backgroundColor = #colorLiteral(red: 0.8375778794, green: 0.7538908124, blue: 0.96424371, alpha: 1)
        
        addSubview(numberLabel)
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        // set the cornerRadius here to make sure it matches the view size
        layer.cornerRadius = min(bounds.height, bounds.width) * 0.5
    }

}

extension RoundView {
    private func setConstraints() {
        NSLayoutConstraint.activate([
            numberLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 18),
            numberLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -18),
            numberLabel.topAnchor.constraint(equalTo: topAnchor, constant: 12),
            numberLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -12),
            
            // let's keep this view at a 1:1 aspect ratio
            self.widthAnchor.constraint(equalTo: self.heightAnchor),
        ])
    }
}

RectangleView

class RectangleView: UIView {
    var textForMainLabel: String
    
    lazy var mainLabel: UILabel = {
        let label = UILabel()
        label.text = "Some text"
        label.font = UIFont.systemFont(ofSize: 18, weight: .regular)
        label.numberOfLines = 0
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    required init(frame: CGRect, textForMainLabel: String) {
        self.textForMainLabel = textForMainLabel
        super.init(frame: frame)
        
        layer.cornerRadius = 30
        translatesAutoresizingMaskIntoConstraints = false
        
        mainLabel.text = textForMainLabel
        
        setupView()
        setConstraints()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupView() {
        backgroundColor = #colorLiteral(red: 0.8718322515, green: 0.8867664933, blue: 0.9465543628, alpha: 1)
        
        addSubview(mainLabel)
    }
}

extension RectangleView {
    private func setConstraints() {
        NSLayoutConstraint.activate([
            mainLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 24),
            mainLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -24),
            mainLabel.topAnchor.constraint(equalTo: topAnchor, constant: 12),
            mainLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -12)
        ])
    }
}

PlayInfoViewController

class PlayInfoViewController: UIViewController {
    private let mainScrollView: UIScrollView = {
        let sv = UIScrollView()
        sv.backgroundColor = UIColor(named: "backgroundColor")
        sv.translatesAutoresizingMaskIntoConstraints = false
        return sv
    }()
    
    private let contentView: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(named: "backgroundColor")
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    // vertical stack view to hold the "rows" of horizontal stack views
    private let vertStackView: UIStackView = {
        let sv = UIStackView()
        sv.axis = .vertical
        sv.spacing = 10
        sv.translatesAutoresizingMaskIntoConstraints = false
        return sv
    }()
    
    private let horisontalStackViews: [UIStackView] = {
        var stackViews: [UIStackView] = []
        let textsForMainLabel = [
            "Draw a grid with three rows and three columns, creating nine squares in total.",
            "Players take turns placing their marker (X or O) in an empty square. To make a move, a player selects a number corresponding to the square where they want to place their marker.",
            "Player X starts by choosing a square (e.g., square 5). Player O follows by choosing an empty square (e.g., square 1). Continue alternating turns until the game ends.",
            "The first player to align three of their markers horizontally, vertically, or diagonally wins. Examples of Winning Combinations: Horizontal: Squares 1, 2, 3 or 4, 5, 6 or 7, 8, 9 Vertical: Squares 1, 4, 7 or 2, 5, 8 or 3, 6, 9 Diagonal: Squares 1, 5, 9 or 3, 5, 7"
        ]
        
        var number = 1
        
        for text in textsForMainLabel {
            let hStackView = UIStackView()
            hStackView.axis = .horizontal
            hStackView.spacing = 20
            hStackView.alignment = .top
            
            let roundView = RoundView (
                frame: CGRect.zero,
                numberOfPosition: number
            )
            let rectView = RectangleView (
                frame: CGRect.zero,
                textForMainLabel: text
            )
            
            hStackView.addArrangedSubview(roundView)
            hStackView.addArrangedSubview(rectView)
            
            stackViews.append(hStackView)
            number += 1
        }
        
        return stackViews
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor(named: "backgroundColor")
        
        setupViews()
        setConstraints()
    }
    
    private func setupViews() {
        view.addSubview(mainScrollView)
        mainScrollView.addSubview(contentView)
        contentView.addSubview(vertStackView)

        for v in horisontalStackViews {
            vertStackView.addArrangedSubview(v)
        }
    }
}

extension PlayInfoViewController {
    private func setConstraints() {
        
        let g = view.safeAreaLayoutGuide
        let cg = mainScrollView.contentLayoutGuide
        let fg = mainScrollView.frameLayoutGuide
        
        NSLayoutConstraint.activate([
            mainScrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            mainScrollView.topAnchor.constraint(equalTo: g.topAnchor, constant: 42),
            mainScrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            mainScrollView.bottomAnchor.constraint(equalTo: g.bottomAnchor),
            
            contentView.leadingAnchor.constraint(equalTo: cg.leadingAnchor),
            contentView.topAnchor.constraint(equalTo: cg.topAnchor),
            contentView.trailingAnchor.constraint(equalTo: cg.trailingAnchor),
            contentView.bottomAnchor.constraint(equalTo: cg.bottomAnchor),
            contentView.widthAnchor.constraint(equalTo: fg.widthAnchor),
            
            // do NOT set contentView.heightAnchor
            
            vertStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 21),
            vertStackView.topAnchor.constraint(equalTo: contentView.topAnchor),
            vertStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -21),
            vertStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
        ])
    }
}

Upvotes: 0

Related Questions