Swift 居中一个UIView而不影响其他UI类在UIKit中以编程方式的位置

Swift 居中一个UIView而不影响其他UI类在UIKit中以编程方式的位置

问题描述

我想通过修改约束属性例如 topAnchor 将一个UIView boardGame: UICollectionView 的位置移动到屏幕中心,但是我对它所做的任何操作似乎都会影响其中的内容。我还定义了一个 UICollectionViewCell 模型,以便可以将单元格注册到 boardGame 作为”唯一的”。

import UIKit

class BoardViewController: UIViewController {

    private let boardGame: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        let board = UICollectionView(frame: .zero, collectionViewLayout: layout)
        board.allowsSelection =  true
        board.register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: "unique")
        board.translatesAutoresizingMaskIntoConstraints = false
        return board
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(boardGame)
        boardGame.backgroundColor = .systemGray2

        boardGame.frame = view.bounds

        let margin: CGFloat = 20
        NSLayoutConstraint.activate([

            boardGame.topAnchor.constraint(equalTo: view.topAnchor, constant: margin),
            boardGame.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                   boardGame.centerYAnchor.constraint(equalTo: view.centerYAnchor),


                   boardGame.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -20),
                   boardGame.heightAnchor.constraint(equalTo: view.widthAnchor, constant: -20),
               ])



        boardGame.delegate = self
        boardGame.dataSource = self

    }

    init() {
           super.init(nibName: nil, bundle: nil)
       }
       required init?(coder: NSCoder) {
           fatalError("init(coder:) has not been implemented")
       }
}

extension BoardViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {


    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 9
    }


    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "unique", for: indexPath) as! CustomCollectionViewCell


              let chessRow = indexPath.row / 3
              if chessRow % 2 == 0 {
                  if indexPath.row % 2 == 0 {
                       cell.backgroundColor = UIColor.white
                  }else{
                      cell.backgroundColor = UIColor.black
                  }
              } else{
                  if indexPath.row % 2 == 0 {
                      cell.backgroundColor = UIColor.black
                  }else{
                      cell.backgroundColor = UIColor.white
                  }
              }

              return cell
          }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
            // Divide the width by 3 to create a 3x3 grid
            let width = collectionView.frame.size.width / 4.0
            let height = width
            return CGSize(width: width, height: height)
        }

}

这里是 CustomCollectionViewCell: UICollectionViewCell 模型:

class CustomCollectionViewCell: UICollectionViewCell {

    let titleLabel = UILabel()

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

        contentView.addSubview(titleLabel)

        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
        titleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
        titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
        titleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

及接收BoardViewController实例的父视图

import UIKit

class MainViewController: UIViewController {

    let boardView = BoardViewController()
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .blue
        addBoardView()
    }

    func addBoardView(){
        addChild(boardView)
        view.addSubview(boardView.view)


        boardView.didMove(toParent: self)
    }
}

我尝试了一下对topAnchor中的constant:CGFloat属性进行调整,以及对boardGame进行了一些调整。为了提供一些上下文,这里是通过boardGame.topAnchor.constraint(equalTo: view.topAnchor, constant: 20),我得到的一个示例,

Swift 居中一个UIView而不影响其他UI类在UIKit中以编程方式的位置

如果我将CGFloat更改为200以使其更加居中,那么它内部的CustomCollectionViewCell的属性将移到边缘,影响顶部边距,如下所示:

Swift 居中一个UIView而不影响其他UI类在UIKit中以编程方式的位置

我已经尝试了一下对CustomCollectionViewCell中的titleLabel的顶部边距约束进行调整,但似乎没有任何作用。

我应该如何保持boardGame视图居中而不影响CustomCollectionViewCell的边距?

解决方案

这些单元格是在集合视图的顶部边缘定位的,因为这就是集合视图的工作方式。这是设计如此。只有当集合视图位于屏幕顶部时,单元格才会显示为“居中”,因为默认情况下单元格的布局会避开安全区域(在这种情况下是动态区域)。

无论如何,您的约束是相互矛盾的。您说boardGame视图应该有固定的宽度和高度(假设父视图的宽度和高度是固定的),其中心点应与父视图的中心点相同(centerX = view.centerX和centerY = view.centerY),并且它的顶部距离父视图的顶部仅为20点。

这些约束无法同时满足。正如您在第一张屏幕截图中所看到的,centerY = view.centerY约束被破坏,以满足其他约束条件。

如果您想让集合视图在垂直和水平方向上都居中,只需移除顶部边距约束即可:

boardGame.topAnchor.constraint(equalTo: view.topAnchor, constant: margin)

如果您还希望单元格在垂直方向上居中,您可以设置contentOffset

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    boardGame.contentOffset.y = (boardGame.contentSize.height - boardGame.bounds.height) / 2
}

那么,如果 boardGame 不应该是可滚动的,请考虑使用一系列 UIStackView 来布局。示例:

class BoardViewController: UIViewController {

    var boardGame: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()

        func makeCell(color: UIColor) -> Cell {
            let cell = Cell(frame: .zero)
            cell.backgroundColor = color
            return cell
        }

        func makeColumn(_ views: [UIView]) -> UIStackView {
            let col = UIStackView(arrangedSubviews: views)
            col.axis = .vertical
            col.spacing = 8
            col.alignment = .center
            col.distribution = .fillEqually
            return col
        }
        let col1 = makeColumn([makeCell(color: .black), makeCell(color: .black), makeCell(color: .black)])
        let col2 = makeColumn([makeCell(color: .white), makeCell(color: .white), makeCell(color: .white)])
        let col3 = makeColumn([makeCell(color: .black), makeCell(color: .black), makeCell(color: .black)])
        let columns = UIStackView(arrangedSubviews: [col1, col2, col3])
        columns.axis = .horizontal
        columns.spacing = 16
        columns.distribution = .fillEqually
        columns.translatesAutoresizingMaskIntoConstraints = false

        boardGame = UIView()
        boardGame.backgroundColor = .gray
        boardGame.addSubview(columns)
        boardGame.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(boardGame)
        NSLayoutConstraint.activate([
            columns.topAnchor.constraint(equalTo: boardGame.topAnchor, constant: 20),
            columns.bottomAnchor.constraint(equalTo: boardGame.bottomAnchor, constant: -20),
            columns.leftAnchor.constraint(equalTo: boardGame.leftAnchor, constant: 8),
            columns.rightAnchor.constraint(equalTo: boardGame.rightAnchor, constant: -8),
            boardGame.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            boardGame.centerYAnchor.constraint(equalTo: view.centerYAnchor),


            boardGame.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -20),
            boardGame.heightAnchor.constraint(equalTo: view.widthAnchor, constant: -20),
        ])
    }

}

class Cell: UIView {

    let titleLabel = UILabel()

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

        addSubview(titleLabel)

        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        titleLabel.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
        titleLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
        titleLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
        titleLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true

        self.translatesAutoresizingMaskIntoConstraints = false
        self.widthAnchor.constraint(equalTo: self.heightAnchor).isActive = true
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程