ฉันเพิ่งเริ่มเรียนรู้เกี่ยวกับ UICollectionViews ฉันสงสัยว่าจะมีใครรู้วิธีระบุจำนวนคอลัมน์ใน collectionview ค่าเริ่มต้นตั้งไว้ที่ 3 (iPhone / แนวตั้ง) ฉันดูเอกสารแล้วดูเหมือนจะหาคำตอบที่กระชับไม่ได้
ฉันเพิ่งเริ่มเรียนรู้เกี่ยวกับ UICollectionViews ฉันสงสัยว่าจะมีใครรู้วิธีระบุจำนวนคอลัมน์ใน collectionview ค่าเริ่มต้นตั้งไว้ที่ 3 (iPhone / แนวตั้ง) ฉันดูเอกสารแล้วดูเหมือนจะหาคำตอบที่กระชับไม่ได้
คำตอบ:
CollectionViews มีประสิทธิภาพมากและมีราคา มากมายและตัวเลือกมากมาย ดังที่ omz กล่าวไว้:
มีหลายวิธีที่คุณสามารถเปลี่ยนจำนวนคอลัมน์
ฉันขอแนะนำให้ใช้<UICollectionViewDelegateFlowLayout>
โปรโตคอลนี้เพื่อให้คุณสามารถเข้าถึงวิธีการต่อไปนี้ซึ่งคุณสามารถควบคุมโครงร่างของคุณได้มากขึ้นUICollectionView
โดยไม่จำเป็นต้องมีคลาสย่อย:
collectionView:layout:insetForSectionAtIndex:
collectionView:layout:minimumInteritemSpacingForSectionAtIndex:
collectionView:layout:minimumLineSpacingForSectionAtIndex:
collectionView:layout:referenceSizeForFooterInSection:
collectionView:layout:referenceSizeForHeaderInSection:
collectionView:layout:sizeForItemAtIndexPath:
นอกจากนี้การใช้วิธีการต่อไปนี้จะบังคับให้ UICollectionView ของคุณอัปเดตเลย์เอาต์เมื่อเปลี่ยนการวางแนว: (บอกว่าคุณต้องการปรับขนาดเซลล์ใหม่สำหรับแนวนอนและทำให้ยืดออก)
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration{
[self.myCollectionView.collectionViewLayout invalidateLayout];
}
นอกจากนี้ยังมีบทช่วยสอนที่ดี 2 บทเกี่ยวกับUICollectionViews
:
http://www.raywenderlich.com/22324/beginning-uicollectionview-in-ios-6-part-12
collectionView:layout:sizeForItemAtIndexPath:
จัดการกับอุปกรณ์ทั้งหมดแยกกันหรือไม่?
new GridLayoutManager(mContext, 4))
(4 คอลัมน์) ง่ายมากหรือแค่ใช้LinearLayoutManager
(แน่นอนว่ามีเพียง 1 คอลัมน์)
ด้วย Swift 5 และ iOS 12.3 คุณสามารถใช้การใช้งาน4 อย่างต่อไปนี้เพื่อกำหนดจำนวนรายการต่อแถวในUICollectionView
ขณะที่จัดการสิ่งที่ใส่เข้าไปและการเปลี่ยนแปลงขนาด (รวมถึงการหมุน)
UICollectionViewFlowLayout
และการใช้UICollectionViewFlowLayout
ของitemSize
สถานที่ให้บริการColumnFlowLayout.swift:
import UIKit
class ColumnFlowLayout: UICollectionViewFlowLayout {
let cellsPerRow: Int
init(cellsPerRow: Int, minimumInteritemSpacing: CGFloat = 0, minimumLineSpacing: CGFloat = 0, sectionInset: UIEdgeInsets = .zero) {
self.cellsPerRow = cellsPerRow
super.init()
self.minimumInteritemSpacing = minimumInteritemSpacing
self.minimumLineSpacing = minimumLineSpacing
self.sectionInset = sectionInset
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepare() {
super.prepare()
guard let collectionView = collectionView else { return }
let marginsAndInsets = sectionInset.left + sectionInset.right + collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right + minimumInteritemSpacing * CGFloat(cellsPerRow - 1)
let itemWidth = ((collectionView.bounds.size.width - marginsAndInsets) / CGFloat(cellsPerRow)).rounded(.down)
itemSize = CGSize(width: itemWidth, height: itemWidth)
}
override func invalidationContext(forBoundsChange newBounds: CGRect) -> UICollectionViewLayoutInvalidationContext {
let context = super.invalidationContext(forBoundsChange: newBounds) as! UICollectionViewFlowLayoutInvalidationContext
context.invalidateFlowLayoutDelegateMetrics = newBounds.size != collectionView?.bounds.size
return context
}
}
CollectionViewController.swift:
import UIKit
class CollectionViewController: UICollectionViewController {
let columnLayout = ColumnFlowLayout(
cellsPerRow: 5,
minimumInteritemSpacing: 10,
minimumLineSpacing: 10,
sectionInset: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
)
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.collectionViewLayout = columnLayout
collectionView?.contentInsetAdjustmentBehavior = .always
collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 59
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.backgroundColor = UIColor.orange
return cell
}
}
UICollectionViewFlowLayout
's itemSize
วิธีimport UIKit
class CollectionViewController: UICollectionViewController {
let margin: CGFloat = 10
let cellsPerRow = 5
override func viewDidLoad() {
super.viewDidLoad()
guard let collectionView = collectionView, let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout else { return }
flowLayout.minimumInteritemSpacing = margin
flowLayout.minimumLineSpacing = margin
flowLayout.sectionInset = UIEdgeInsets(top: margin, left: margin, bottom: margin, right: margin)
collectionView.contentInsetAdjustmentBehavior = .always
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
}
override func viewWillLayoutSubviews() {
guard let collectionView = collectionView, let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else { return }
let marginsAndInsets = flowLayout.sectionInset.left + flowLayout.sectionInset.right + collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right + flowLayout.minimumInteritemSpacing * CGFloat(cellsPerRow - 1)
let itemWidth = ((collectionView.bounds.size.width - marginsAndInsets) / CGFloat(cellsPerRow)).rounded(.down)
flowLayout.itemSize = CGSize(width: itemWidth, height: itemWidth)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 59
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.backgroundColor = UIColor.orange
return cell
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
collectionView?.collectionViewLayout.invalidateLayout()
super.viewWillTransition(to: size, with: coordinator)
}
}
UICollectionViewDelegateFlowLayout
's collectionView(_:layout:sizeForItemAt:)
วิธีimport UIKit
class CollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let inset: CGFloat = 10
let minimumLineSpacing: CGFloat = 10
let minimumInteritemSpacing: CGFloat = 10
let cellsPerRow = 5
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.contentInsetAdjustmentBehavior = .always
collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: inset, left: inset, bottom: inset, right: inset)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return minimumLineSpacing
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return minimumInteritemSpacing
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let marginsAndInsets = inset * 2 + collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right + minimumInteritemSpacing * CGFloat(cellsPerRow - 1)
let itemWidth = ((collectionView.bounds.size.width - marginsAndInsets) / CGFloat(cellsPerRow)).rounded(.down)
return CGSize(width: itemWidth, height: itemWidth)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 59
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.backgroundColor = UIColor.orange
return cell
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
collectionView?.collectionViewLayout.invalidateLayout()
super.viewWillTransition(to: size, with: coordinator)
}
}
UICollectionViewFlowLayout
และการใช้UICollectionViewFlowLayout
ของestimatedItemSize
สถานที่ให้บริการCollectionViewController.swift:
import UIKit
class CollectionViewController: UICollectionViewController {
let items = [
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"Lorem ipsum dolor sit amet, consectetur.",
"Lorem ipsum dolor sit amet.",
"Lorem ipsum dolor sit amet, consectetur.",
"Lorem ipsum dolor sit amet, consectetur adipiscing.",
"Lorem ipsum.",
"Lorem ipsum dolor sit amet.",
"Lorem ipsum dolor sit.",
"Lorem ipsum dolor sit amet, consectetur adipiscing.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.",
"Lorem ipsum dolor sit amet, consectetur."
]
let columnLayout = FlowLayout(
cellsPerRow: 3,
minimumInteritemSpacing: 10,
minimumLineSpacing: 10,
sectionInset: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
)
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.collectionViewLayout = columnLayout
collectionView?.contentInsetAdjustmentBehavior = .always
collectionView?.register(Cell.self, forCellWithReuseIdentifier: "Cell")
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
cell.label.text = items[indexPath.row]
return cell
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
collectionView?.collectionViewLayout.invalidateLayout()
super.viewWillTransition(to: size, with: coordinator)
}
}
FlowLayout.swift:
import UIKit
class FlowLayout: UICollectionViewFlowLayout {
let cellsPerRow: Int
required init(cellsPerRow: Int = 1, minimumInteritemSpacing: CGFloat = 0, minimumLineSpacing: CGFloat = 0, sectionInset: UIEdgeInsets = .zero) {
self.cellsPerRow = cellsPerRow
super.init()
self.minimumInteritemSpacing = minimumInteritemSpacing
self.minimumLineSpacing = minimumLineSpacing
self.sectionInset = sectionInset
estimatedItemSize = UICollectionViewFlowLayout.automaticSize
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard let layoutAttributes = super.layoutAttributesForItem(at: indexPath) else { return nil }
guard let collectionView = collectionView else { return layoutAttributes }
let marginsAndInsets = collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right + sectionInset.left + sectionInset.right + minimumInteritemSpacing * CGFloat(cellsPerRow - 1)
layoutAttributes.bounds.size.width = ((collectionView.bounds.width - marginsAndInsets) / CGFloat(cellsPerRow)).rounded(.down)
return layoutAttributes
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let superLayoutAttributes = super.layoutAttributesForElements(in: rect)!.map { $0.copy() as! UICollectionViewLayoutAttributes }
guard scrollDirection == .vertical else { return superLayoutAttributes }
let layoutAttributes = superLayoutAttributes.compactMap { layoutAttribute in
return layoutAttribute.representedElementCategory == .cell ? layoutAttributesForItem(at: layoutAttribute.indexPath) : layoutAttribute
}
// (optional) Uncomment to top align cells that are on the same line
/*
let cellAttributes = layoutAttributes.filter({ $0.representedElementCategory == .cell })
for (_, attributes) in Dictionary(grouping: cellAttributes, by: { ($0.center.y / 10).rounded(.up) * 10 }) {
guard let max = attributes.max(by: { $0.size.height < $1.size.height }) else { continue }
for attribute in attributes where attribute.size.height != max.size.height {
attribute.frame.origin.y = max.frame.origin.y
}
}
*/
// (optional) Uncomment to bottom align cells that are on the same line
/*
let cellAttributes = layoutAttributes.filter({ $0.representedElementCategory == .cell })
for (_, attributes) in Dictionary(grouping: cellAttributes, by: { ($0.center.y / 10).rounded(.up) * 10 }) {
guard let max = attributes.max(by: { $0.size.height < $1.size.height }) else { continue }
for attribute in attributes where attribute.size.height != max.size.height {
attribute.frame.origin.y += max.frame.maxY - attribute.frame.maxY
}
}
*/
return layoutAttributes
}
}
Cell.swift:
import UIKit
class Cell: UICollectionViewCell {
let label = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
label.numberOfLines = 0
backgroundColor = .orange
contentView.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor).isActive = true
label.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
layoutIfNeeded()
label.preferredMaxLayoutWidth = label.bounds.size.width
layoutAttributes.bounds.size.height = contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
return layoutAttributes
}
// Alternative implementation
/*
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
label.preferredMaxLayoutWidth = layoutAttributes.size.width - contentView.layoutMargins.left - contentView.layoutMargins.right
layoutAttributes.bounds.size.height = contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
return layoutAttributes
}
*/
}
ฉันใช้งานUICollectionViewDelegateFlowLayout
กับฉันUICollectionViewController
และแทนที่วิธีการที่รับผิดชอบในการกำหนดขนาดของเซลล์ จากนั้นฉันก็เอาความกว้างของหน้าจอมาหารกับความต้องการคอลัมน์ของฉัน ตัวอย่างเช่นฉันต้องการให้มี 3 คอลัมน์ในแต่ละขนาดหน้าจอ นี่คือลักษณะของรหัสของฉัน -
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
float cellWidth = screenWidth / 3.0; //Replace the divisor with the column count requirement. Make sure to have it in float.
CGSize size = CGSizeMake(cellWidth, cellWidth);
return size;
}
ขยายคำตอบของ noob:
func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let totalSpace = flowLayout.sectionInset.left
+ flowLayout.sectionInset.right
+ (flowLayout.minimumInteritemSpacing * CGFloat(numberOfItemsPerRow - 1))
let size = Int((collectionView.bounds.width - totalSpace) / CGFloat(numberOfItemsPerRow))
return CGSize(width: size, height: size)
}
สิ่งนี้ช่วยให้สามารถเว้นระยะห่างระหว่างเซลล์ได้ มันถือว่าInt
ตัวแปรสมาชิกที่เรียกว่าnumberOfItemsPerRow
และเซลล์ทั้งหมดเป็นสี่เหลี่ยมจัตุรัสและมีขนาดเท่ากัน ตามที่ระบุไว้ในคำตอบของ jhilgert00 เรายังต้องตอบสนองต่อการเปลี่ยนแปลงการวางแนว แต่ตอนนี้ใช้viewWillTransitionToSize
ตามที่willRotateToInterfaceOrientation
คิดค่าเสื่อมราคา
นี่คือรหัสการทำงานสำหรับ Swift 3 ที่มีเค้าโครงสองคอลัมน์:
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let nbCol = 2
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let totalSpace = flowLayout.sectionInset.left
+ flowLayout.sectionInset.right
+ (flowLayout.minimumInteritemSpacing * CGFloat(nbCol - 1))
let size = Int((collectionView.bounds.width - totalSpace) / CGFloat(nbCol))
return CGSize(width: size, height: size)
}
อย่าลังเลที่จะเปลี่ยน "nbCol" เป็นจำนวนคอลัมน์ที่คุณต้องการ
หากคุณขี้เกียจใช้ delegate
extension UICollectionView {
func setItemsInRow(items: Int) {
if let layout = self.collectionViewLayout as? UICollectionViewFlowLayout {
let contentInset = self.contentInset
let itemsInRow: CGFloat = CGFloat(items);
let innerSpace = layout.minimumInteritemSpacing * (itemsInRow - 1.0)
let insetSpace = contentInset.left + contentInset.right + layout.sectionInset.left + layout.sectionInset.right
let width = floor((CGRectGetWidth(frame) - insetSpace - innerSpace) / itemsInRow);
layout.itemSize = CGSizeMake(width, width)
}
}
}
PS: ควรเรียกว่าหลังการหมุนด้วยนะ
อัปเดตเป็น Swift 3:
แทนที่จะใช้เค้าโครงโฟลว์ฉันชอบใช้เค้าโครงที่กำหนดเองสำหรับหมายเลขคอลัมน์และหมายเลขแถวที่เฉพาะเจาะจง เพราะ:
เซลล์ปกติและเซลล์ส่วนหัว: (เพิ่ม UILabel เป็น IBOutlet ใน xib ของคุณ):
class CollectionViewCell: UICollectionViewCell {
@IBOutlet weak var label: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.backgroundColor = UIColor.black
label.textColor = UIColor.white
}
}
class CollectionViewHeadCell: UICollectionViewCell {
@IBOutlet weak var label: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.backgroundColor = UIColor.darkGray
label.textColor = UIColor.white
}
}
เค้าโครงที่กำหนดเอง:
let cellHeight: CGFloat = 100
let cellWidth: CGFloat = 100
class CustomCollectionViewLayout: UICollectionViewLayout {
private var numberOfColumns: Int!
private var numberOfRows: Int!
// It is two dimension array of itemAttributes
private var itemAttributes = [[UICollectionViewLayoutAttributes]]()
// It is one dimension of itemAttributes
private var cache = [UICollectionViewLayoutAttributes]()
override func prepare() {
if self.cache.isEmpty {
self.numberOfColumns = self.collectionView?.numberOfItems(inSection: 0)
self.numberOfRows = self.collectionView?.numberOfSections
// Dynamically change cellWidth if total cell width is smaller than whole bounds
/* if (self.collectionView?.bounds.size.width)!/CGFloat(self.numberOfColumns) > cellWidth {
self.cellWidth = (self.collectionView?.bounds.size.width)!/CGFloat(self.numberOfColumns)
}
*/
for row in 0..<self.numberOfRows {
var row_temp = [UICollectionViewLayoutAttributes]()
for column in 0..<self.numberOfColumns {
let indexPath = NSIndexPath(item: column, section: row)
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath as IndexPath)
attributes.frame = CGRect(x: cellWidth*CGFloat(column), y: cellHeight*CGFloat(row), width: cellWidth, height: cellHeight)
row_temp.append(attributes)
self.cache.append(attributes)
}
self.itemAttributes.append(row_temp)
}
}
}
override var collectionViewContentSize: CGSize {
return CGSize(width: CGFloat(self.numberOfColumns)*cellWidth, height: CGFloat(self.numberOfRows)*cellHeight)
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var layoutAttributes = [UICollectionViewLayoutAttributes]()
for attributes in cache {
if attributes.frame.intersects(rect) {
layoutAttributes.append(attributes)
}
}
return layoutAttributes
}
}
คอลเลกชันดู:
let CellIdentifier = "CellIdentifier"
let HeadCellIdentifier = "HeadCellIdentifier"
class CollectionView: UICollectionView, UICollectionViewDelegate, UICollectionViewDataSource {
init() {
let layout = CustomCollectionViewLayout()
super.init(frame: CGRect.zero, collectionViewLayout: layout)
self.register(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier: CellIdentifier)
self.register(UINib(nibName: "CollectionViewHeadCell", bundle: nil), forCellWithReuseIdentifier: HeadCellIdentifier)
self.isDirectionalLockEnabled = true
self.dataSource = self
self.delegate = self
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func updateCollectionView() {
DispatchQueue.main.async {
self.reloadData()
}
}
// MARK: CollectionView datasource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 20
}
override func numberOfItems(inSection section: Int) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let column = (indexPath as NSIndexPath).row
let row = (indexPath as NSIndexPath).section
if column == 0 {
let cell : CollectionViewHeadCell = collectionView.dequeueReusableCell(withReuseIdentifier: HeadCellIdentifier, for: indexPath) as! CollectionViewHeadCell
cell.label.text = "\(row)"
return cell
}
else if row == 0 {
let cell : CollectionViewHeadCell = collectionView.dequeueReusableCell(withReuseIdentifier: HeadCellIdentifier, for: indexPath) as! CollectionViewHeadCell
cell.label.text = "\(column)"
return cell
}
else {
let cell : CollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: CellIdentifier, for: indexPath) as! CollectionViewCell
cell.label.text = String(format: "%d", arguments: [indexPath.section*indexPath.row])
return cell
}
}
// MARK: CollectionView delegate
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let column = (indexPath as NSIndexPath).row
let row = (indexPath as NSIndexPath).section
print("\(column) \(row)")
}
}
ใช้ CollectionView จาก ViewController:
class ViewController: UIViewController {
let collectionView = CollectionView()
override func viewDidLoad() {
collectionView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(collectionView)
self.view.backgroundColor = UIColor.red
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[collectionView]|", options: [], metrics: nil, views: ["collectionView": collectionView]))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[collectionView]|", options: [], metrics: nil, views: ["collectionView": collectionView]))
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
collectionView.updateCollectionView()
}
}
ในที่สุดคุณก็มี CollectionView แฟนซี!
เพราะ UICollectionView
มีความยืดหยุ่นจึงมีหลายวิธีที่คุณสามารถเปลี่ยนจำนวนคอลัมน์ขึ้นอยู่กับประเภทของเค้าโครงที่คุณใช้
UICollectionViewFlowLayout
(ซึ่งอาจเป็นสิ่งที่คุณกำลังทำงานกับ) ไม่ได้ระบุจำนวนคอลัมน์โดยตรง (เพราะมันขึ้นอยู่กับมุมมองขนาด / ปฐมนิเทศ) วิธีที่ง่ายที่สุดที่จะเปลี่ยนมันจะกำหนดitemSize
คุณสมบัติและ / หรือ/minimumInteritemSpacing
minimumLineSpacing
Swift 3.0 ใช้งานได้ทั้งทิศทางการเลื่อนแนวนอนและแนวตั้งและระยะห่างตัวแปร
ระบุจำนวนคอลัมน์
let numberOfColumns: CGFloat = 3
กำหนดค่าflowLayout
เพื่อแสดงผลที่ระบุnumberOfColumns
if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
let horizontalSpacing = flowLayout.scrollDirection == .vertical ? flowLayout.minimumInteritemSpacing : flowLayout.minimumLineSpacing
let cellWidth = (collectionView.frame.width - max(0, numberOfColumns - 1)*horizontalSpacing)/numberOfColumns
flowLayout.itemSize = CGSize(width: cellWidth, height: cellWidth)
}
อัปเดตเป็น Swift 5+ iOS 13
Collectionview ขนาดโดยประมาณต้องไม่มี
ประกาศระยะขอบสำหรับเซลล์
let margin: CGFloat = 10
ในการกำหนดค่า viewDidLoad minimumInteritemSpacing
, minimumLineSpacing
,sectionInset
guard let collectionView = docsColl, let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else { return }
flowLayout.minimumInteritemSpacing = margin
flowLayout.minimumLineSpacing = margin
flowLayout.sectionInset = UIEdgeInsets(top: margin, left: margin, bottom: margin, right: margin)
วิธีUICollectionViewDataSourcesizeForItemAt
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let noOfCellsInRow = 2 //number of column you want
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let totalSpace = flowLayout.sectionInset.left
+ flowLayout.sectionInset.right
+ (flowLayout.minimumInteritemSpacing * CGFloat(noOfCellsInRow - 1))
let size = Int((collectionView.bounds.width - totalSpace) / CGFloat(noOfCellsInRow))
return CGSize(width: size, height: size)
}
ทุกอย่างเกี่ยวกับเค้าโครงที่คุณต้องการวาด คุณสามารถสร้างคลาสแบบกำหนดเองที่สืบทอดจาก UICollectionViewFlowLayout ขณะนี้ยังไม่มีวิธีการตั้งค่าคอลัมน์โดยตรง หากคุณต้องการใช้งานฟังก์ชันนี้คุณต้องดำเนินการด้วยตนเอง คุณต้องจัดการในคลาสเค้าโครงโฟลว์ที่กำหนดเอง
ตอนนี้จะเกิดคำถามว่าคุณจะทำอย่างไร? หากคุณไม่ต้องการรบกวนกรอบเซลล์คุณสามารถปรับเปลี่ยนได้
collectionView:layout:minimumInteritemSpacingForSectionAtIndex:
collectionView:layout:minimumLineSpacingForSectionAtIndex:
อีกวิธีหนึ่งคือระบุตำแหน่งของเซลล์ให้คุณเอง โดยการลบล้างสองวิธีด้านล่างซึ่งจะถูกเรียกในระหว่างการสร้างเค้าโครงของคุณ
- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path
UICollectionViewLayoutAttributes เป็นคลาสที่จะจัดการกับตำแหน่งเซลล์เฟรม Zindex เป็นต้น
คำตอบนี้สำหรับ swift 3.0 ->
ก่อนอื่นให้สอดคล้องกับโปรโตคอล:
UICollectionViewDelegateFlowLayout
จากนั้นเพิ่มวิธีการเหล่านี้:
//this method is for the size of items
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.frame.width/3
let height : CGFloat = 160.0
return CGSize(width: width, height: height)
}
//these methods are to configure the spacing between items
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(0,0,0,0)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
ฉันแค่อยากต่อท้ายคำตอบของ Imanou Petit # 2 เพื่อให้แน่ใจว่าระยะขอบมีความแน่นอนโดยไม่คำนึงถึงความกว้างของหน้าจอฉันใช้ตัวแก้ซ้ำกับระยะขอบที่ต้องการและ # ของคอลัมน์เป็นอินพุต ฉันยังได้เพิ่มธงทิศทางว่าจะเทียบระยะขอบสุดท้ายกับเป้าหมายของพวกเขาอย่างไร
ตัวแก้ซ้ำจะแสดงด้านล่างและส่งกลับ cellWidth และ margin
private func iterativeCellSpacing(targetMargins : CGFloat,
cellsPerRow : Int,
isMinTarget : Bool) -> (CGFloat, CGFloat)
{
var w : CGFloat = 0
var m : CGFloat = targetMargins
let cols : CGFloat = CGFloat(cellsPerRow)
let numMargins : CGFloat = cols + 1.0
let screenWidth : CGFloat = collectionView!.bounds.size.width
var delta = CGFloat.greatestFiniteMagnitude
while abs(delta) > 0.001
{
let totalMarginSpacing = numMargins * m
let totalCellSpacing = screenWidth - totalMarginSpacing
if (isMinTarget)
{
w = floor(totalCellSpacing / cols)
m = ceil((screenWidth - cols * w) / numMargins)
}
else
{
w = ceil(totalCellSpacing / cols)
m = floor((screenWidth - cols * w) / numMargins)
}
delta = screenWidth - w * CGFloat(cellsPerRow) - m * numMargins
}
return (w, m)
}
ฉันเรียกมันว่า:
fileprivate var margin: CGFloat = 20
fileprivate var cellWidth : CGFloat = 80
fileprivate let cellsPerRow = 4
override func viewDidLoad()
{
super.viewDidLoad()
(cellWidth, margin) = iterativeCellSpacing(targetMargins: margin, cellsPerRow: 4, isMinTarget: true)
...
}
จากนั้นฉันใช้ค่า cellWidth และ margin กับเค้าโครงโฟลว์ดังนี้:
extension MyCollectionController : UICollectionViewDelegateFlowLayout
{func collectionView (_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {return CGSize (width: cellWidth, height: cellWidth)}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
collectionView?.collectionViewLayout.invalidateLayout()
super.viewWillTransition(to: size, with: coordinator)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets
{
return UIEdgeInsetsMake(margin, margin, margin, margin)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat
{
return margin
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat
{
return margin
}
}
หวังว่านี่จะช่วยได้ อาจมีวิธีที่ง่ายกว่าในการตรวจสอบว่าระยะขอบมีความแน่นอน แต่นี่เป็นวิธีหนึ่ง นอกจากนี้รหัสนี้ยังไม่ได้รับการทดสอบสำหรับอุปกรณ์ที่อนุญาตให้มีการหมุนเวียนมุมมอง
ขอบคุณ
ทางออกที่ดีที่สุดคือการใช้ UICollectionViewDelegateFlowLayout แต่คุณสามารถคำนวณความกว้างของเซลล์และแบ่งตามจำนวนคอลัมน์ที่คุณต้องการได้อย่างง่ายดาย
เคล็ดลับคือการสร้างความกว้างโดยไม่มีเศษส่วน
(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat screenWidth = self.view.frame.size.width;
CGFloat marginWidth = (screenWidth - collectionView.frame.size.width);
CGFloat cellWith = (collectionView.frame.size.width - marginWidth )/3;
cellWith= floorf(cellWith);
CGSize retval = CGSizeMake(cellWith,cellWith);
return retval;}
ฉันสร้างเค้าโครงคอลเลกชัน
ในการทำให้ตัวคั่นสามารถมองเห็นได้ให้ตั้งค่าสีพื้นหลังของมุมมองคอลเลคชันเป็นสีเทา หนึ่งแถวต่อส่วน
การใช้งาน:
let layout = GridCollectionViewLayout()
layout.cellHeight = 50 // if not set, cellHeight = Collection.height/numberOfSections
layout.cellWidth = 50 // if not set, cellWidth = Collection.width/numberOfItems(inSection)
collectionView.collectionViewLayout = layout
เค้าโครง:
import UIKit
class GridCollectionViewLayout: UICollectionViewLayout {
var cellWidth : CGFloat = 0
var cellHeight : CGFloat = 0
var seperator: CGFloat = 1
private var cache = [UICollectionViewLayoutAttributes]()
override func prepare() {
guard let collectionView = self.collectionView else {
return
}
self.cache.removeAll()
let numberOfSections = collectionView.numberOfSections
if cellHeight <= 0
{
cellHeight = (collectionView.bounds.height - seperator*CGFloat(numberOfSections-1))/CGFloat(numberOfSections)
}
for section in 0..<collectionView.numberOfSections {
let numberOfItems = collectionView.numberOfItems(inSection: section)
let cellWidth2 : CGFloat
if cellWidth <= 0
{
cellWidth2 = (collectionView.bounds.width - seperator*CGFloat(numberOfItems-1))/CGFloat(numberOfItems)
}
else
{
cellWidth2 = cellWidth
}
for row in 0..<numberOfItems {
let indexPath = NSIndexPath(row: row, section: section)
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath as IndexPath)
attributes.frame = CGRect(x: (cellWidth2+seperator)*CGFloat(row),
y: (cellHeight+seperator)*CGFloat(section),
width: cellWidth2,
height: cellHeight)
//row_temp.append(attributes)
self.cache.append(attributes)
}
//self.itemAttributes.append(row_temp)
}
}
override var collectionViewContentSize: CGSize {
guard let collectionView = collectionView else
{
return CGSize.zero
}
if (collectionView.numberOfSections <= 0)
{
return collectionView.bounds.size
}
let width:CGFloat
if cellWidth <= 0
{
width = collectionView.bounds.width
}
else
{
width = cellWidth*CGFloat(collectionView.numberOfItems(inSection: 0))
}
let numberOfSections = CGFloat(collectionView.numberOfSections)
var height:CGFloat = 0
height += numberOfSections * cellHeight
height += (numberOfSections - 1) * seperator
return CGSize(width: width, height: height)
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var layoutAttributes = [UICollectionViewLayoutAttributes]()
for attributes in cache {
if attributes.frame.intersects(rect) {
layoutAttributes.append(attributes)
}
}
return layoutAttributes
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cache[indexPath.item]
}
}
ลองนี่มันใช้งานได้ดีสำหรับฉัน
ทำตามขั้นตอนด้านล่าง:
1. กำหนดค่าในไฟล์. h
#define kNoOfColumsForCollection 3
#define kNoOfRowsForCollection 4
#define kcellSpace 5
#define kCollectionViewCellWidth (self.view.frame.size.width - kcellSpace*kNoOfColumsForCollection)/kNoOfColumsForCollection
#define kCollectionViewCellHieght (self.view.frame.size.height-40- kcellSpace*kNoOfRowsForCollection)/kNoOfRowsForCollection
หรือ
#define kNoOfColumsForCollection 3
#define kCollectionViewCellWidthHieght (self.view.frame.size.width - 6*kNoOfColumsForCollection)/kNoOfColumsForCollection
2. เพิ่มรหัสในคอลเลกชัน View Layout แหล่งข้อมูลวิธีการดังต่อไปนี้
#pragma mark Collection View Layout data source methods
// collection view with autolayout
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return 4;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return 1;
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(4, 4, 4, 4);
}
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return
CGSizeMake(kCollectionViewCellWidth,kCollectionViewCellHieght);
// CGSizeMake (kCollectionViewCellWidthHieght,kCollectionViewCellWidthHieght);
}
หวังว่านี่จะเป็นความช่วยเหลือสำหรับบางคน
ขั้นแรกให้เพิ่มUICollectionViewDelegateFlowLayoutเป็นโปรโตคอล
จากนั้น:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
{
var columnCount = 3
let width = (view.frame.width - 20) / columnCount
return CGSize(width: width, height: width)
}
UICollectionView
เป็นกริดโดยทั่วไปเพราะฉันรู้ว่าฉันต้องการแค่ 4 คอลัมน์ ฉันทำสิ่งนี้โดยทำให้เซลล์ของฉันมีขนาดที่แน่นอนและระยะห่างระหว่างเซลล์เหล่านี้มีขนาดที่แน่นอนเพื่อให้คอลเลกชันวิวแสดงเพียง 4 คอลัมน์ไม่ว่าจะวางในแนวใด สิ่งนี้คล้ายกับสิ่งที่คุณต้องการหรือไม่?