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

问题描述 投票:0回答:1

我想通过修改约束属性(例如

boardGame: UICollectionView
)将 UIView
topAnchor
的位置移动到屏幕的中心,但我对其所做的任何操作似乎都会影响其中的内容。我还定义了一个
UICollectionViewCell
模型,这样我就可以将
boardGame
中的单元格注册为“uinique”。

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)
    }
}

我尝试过使用

constant: CGFloat
topAnchor
boardGame
的属性。这里提供一些背景信息,这是我通过
boardGame.topAnchor.constraint(equalTo: view.topAnchor, constant: 20)
,

得到的示例

如果我将

CGFloat
更改为 200 以使其更加居中,则其内部
CustomCollectionViewCell
的属性会移动到影响上边距的边缘,如下所示:

我已经尝试弄乱

titleLabel
顶部边距
constraint
内部
CustomCollectionViewCell
但似乎没有做任何事情。

如何才能使

boardGame
视图保持在中心而不影响
CustomCollectionViewCell
的边缘?

swift uicollectionview uikit uicollectionviewcell
1个回答
0
投票

单元格位于集合视图的顶部边缘,因为这就是集合视图的工作方式。这是设计使然。当集合视图位于屏幕顶部时,单元格仅出现“居中”,因为默认情况下单元格的布局是为了避开安全区域(在本例中为动态岛)。

无论如何,你的约束都是矛盾的。你是说

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

© www.soinside.com 2019 - 2024. All rights reserved.