代码之家  ›  专栏  ›  技术社区  ›  willd

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

  •  0
  • willd  · 技术社区  · 2 年前

    我想移动UIView的位置 boardGame: UICollectionView 通过修改约束属性(例如 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 在里面 顶部锚 在里面 棋盘游戏 .这里举一个例子来说明我的理解 boardGame.topAnchor.constraint(equalTo: view.topAnchor, constant: 20) ,

    enter image description here

    如果我更改 CGFloat 到200,使其更加集中 CustomCollectionViewCell 在里面,它移动到边缘,像这样影响顶部边缘:

    enter image description here

    我已经试过了 titleLabel 上边距 constraint 的内部 自定义集合视图单元格 但似乎什么也没做。

    我怎么能保留 棋盘游戏 在不影响 自定义集合视图单元格 ?

    1 回复  |  直到 2 年前
        1
  •  0
  •   Sweeper    2 年前

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

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

    这些不可能同时得到满足。正如您在第一张屏幕截图中看到的 centerY=视图中心Y 约束被打破,以满足其他约束。

    如果希望集合视图垂直和水平居中,只需删除上边距约束即可:

    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
    }
    

    也就是说,如果 棋盘游戏 不应该是可滚动的,请考虑使用 UIStackView s用于此布局。示例:

    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")
        }
    }
    
    推荐文章