iOS UICollectionView如何创建内部具有不同大小的项目的水平滚动矩形布局。
我想使用UICollectionView创建矩形布局,如下所示。我该如何实现?
UICollectionView
水平滚动
矩形布局
每个项目的宽度和高度相对于屏幕大小都是固定的。
以下是320 * 480 iPhone分辨率的尺寸。下面更新了屏幕。
Item 1 Size is - (213*148)
Item 2 Size is - (106*75)
Item 3 Size is - (106*74)
Item 4 Size is - (106*88)
Item 5 Size is - (106*88)
Item 6 Size is - (106*88)
Item 7 Size is - (320*237)
Item 8 Size is - (320*237)
Item 9 Size is - (320*237)
例如,在第6项之后,每个项的尺寸为320 * 237
如何为上述UI设计创建自定义布局?
必须感谢您提供快速的解决方案。预先感谢。
我建议在CollectionViewCell(固定尺寸)内部使用StackView来创建网格布局,如您的帖子中所示。
在GridStackView
下方,根据使用方法addCell(view: UIView)
添加的视图数创建动态网格布局。
将此GridStackView
添加为CollectionViewCell的唯一子视图,将所有边缘固定到侧面,以便完全填充CollectionViewCell。
[准备CollectionViewCell时,使用方法addCell(view: UIView)
向其中添加图块视图。
如果仅添加一个视图,则它将显示单个视图,该视图占据整个GridStackView
,并占据整个CollectionViewCell。如果添加了多个视图,它将自动将它们布置在CollectionViewCell内部。
您可以调整下面的代码以获得所需的布局,以计算行和列。当前的实现需要在初始化时提供rowSize
,我将其用于我的一个项目,您需要对其进行一些修改以获取所需的布局。
class GridStackView: UIStackView {
private var cells: [UIView] = []
private var currentRow: UIStackView?
var rowSize: Int = 3
var defaultSpacing: CGFloat = 5
init(rowSize: Int) {
self.rowSize = rowSize
super.init(frame: .zero)
translatesAutoresizingMaskIntoConstraints = false
axis = .vertical
spacing = defaultSpacing
distribution = .fillEqually
}
required init(coder: NSCoder) {
super.init(coder: coder)
translatesAutoresizingMaskIntoConstraints = false
axis = .vertical
spacing = defaultSpacing
distribution = .fillEqually
}
private func preapreRow() -> UIStackView {
let row = UIStackView(arrangedSubviews: [])
row.spacing = defaultSpacing
row.translatesAutoresizingMaskIntoConstraints = false
row.axis = .horizontal
row.distribution = .fillEqually
return row
}
func removeAllCell() {
for item in arrangedSubviews {
item.removeFromSuperview()
}
cells.removeAll()
currentRow = nil
}
func addCell(view: UIView) {
let firstCellInRow = cells.count % rowSize == 0
if currentRow == nil || firstCellInRow {
currentRow = preapreRow()
addArrangedSubview(currentRow!)
}
view.translatesAutoresizingMaskIntoConstraints = false
cells.append(view)
currentRow?.addArrangedSubview(view)
setNeedsLayout()
}
}
当我使用下面的代码时,我得到的输出如下。
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setUpCollectionView()
// Do any additional setup after loading the view.
}
func setUpCollectionView() {
self.view.backgroundColor = .white
let layout = UICollectionViewFlowLayout()
// layout.minimumInteritemSpacing = 1
// layout.minimumLineSpacing = 1
layout.scrollDirection = .horizontal
let collectionView = CollectionView(frame: .zero, collectionViewLayout: layout)
view.addSubview(collectionView)
collectionView.bounces = false
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
collectionView.heightAnchor.constraint(equalToConstant: 240).isActive = true
collectionView.translatesAutoresizingMaskIntoConstraints = false
}
}
class CollectionView: UICollectionView {
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
self.register(CollectionViewCell.self, forCellWithReuseIdentifier: CollectionViewCell.identifier)
self.dataSource = self
self.delegate = self
self.isPagingEnabled = true
}
required init?(coder: NSCoder) {
fatalError()
}
}
extension CollectionView: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionViewCell.identifier, for: indexPath) as! CollectionViewCell
cell.backgroundColor = .blue
cell.label.text = "\(indexPath.row)"
let row = indexPath.row
switch row {
case 0:
cell.backgroundColor = .red
case 1:
cell.backgroundColor = .blue
case 2:
cell.backgroundColor = .purple
case 3:
cell.backgroundColor = .orange
case 4:
cell.backgroundColor = .cyan
case 5:
cell.backgroundColor = .green
case 6:
cell.backgroundColor = .magenta
case 7:
cell.backgroundColor = .white
case 8:
cell.backgroundColor = .blue
case 9:
cell.backgroundColor = .green
default:
cell.backgroundColor = .systemPink
}
return cell
}
}
extension CollectionView: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let row = indexPath.row
let width = collectionView.frame.width
let other = width / 3
let height = collectionView.frame.height
let o_height = height / 3
switch row {
case 0:
return CGSize(width: other * 2, height: o_height * 2)
case 1:
return CGSize(width: other * 2, height: o_height)
case 2:
return CGSize(width: other, height: o_height)
case 3:
return CGSize(width: other, height: o_height)
case 4:
return CGSize(width: other, height: o_height)
case 5, 6, 7:
return CGSize(width: other, height: o_height)
default:
return CGSize(width: width, height: height)
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return .leastNormalMagnitude
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return .leastNormalMagnitude
}
}
class CollectionViewCell: UICollectionViewCell {
static let identifier = "CollectionViewCell"
let label = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
self.contentView.addSubview(label)
label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
label.translatesAutoresizingMaskIntoConstraints = false
}
required init?(coder: NSCoder) {
fatalError()
}
}