Ios UICollectionView设置列数
我刚开始学习UICollectionView。我想知道是否有人知道如何指定collectionview中的列数。默认设置为3(iPhone/纵向)。我看了文档,似乎找不到一个简洁的答案。因为Ios UICollectionView设置列数,ios,objective-c,xcode,uicollectionview,uicollectionviewcell,Ios,Objective C,Xcode,Uicollectionview,Uicollectionviewcell,我刚开始学习UICollectionView。我想知道是否有人知道如何指定collectionview中的列数。默认设置为3(iPhone/纵向)。我看了文档,似乎找不到一个简洁的答案。因为UICollectionView非常灵活,有多种方法可以更改列数,具体取决于您使用的布局类型 UICollectionViewFlowLayout(这可能是您正在使用的)没有直接指定列数(因为它取决于视图大小/方向)。更改它的最简单方法是设置itemSize属性和/或minimumInteritemSpaci
UICollectionView
非常灵活,有多种方法可以更改列数,具体取决于您使用的布局类型
UICollectionViewFlowLayout
(这可能是您正在使用的)没有直接指定列数(因为它取决于视图大小/方向)。更改它的最简单方法是设置itemSize
属性和/或minimumInteritemSpacing
/minimumLineSpacing
CollectionView功能强大,而且价格低廉。很多,很多选择。正如欧姆兹所说:
有多种方法可以更改列数
let numberOfColumns: CGFloat = 3
我建议实施该协议,让您可以访问以下方法,在这些方法中,您可以更好地控制UICollectionView
的布局,而无需对其进行子类化:
collectionView:layout:insetforsessionatindex:
collectionView:layout:minimuminetemspacingforsectionindex:
collectionView:layout:minimumlinespacingforsection索引:
collectionView:layout:referenceSizeForFooterInSection:
collectionView:layout:referenceSizeForHeaderInstruction:
collectionView:layout:sizeFormiteIndeXPath:
UICollectionViews
的非常好的教程:
这一切都是关于你想要绘制的布局。您可以创建从UICollectionViewFlowLayout继承的自定义类。目前没有任何直接方法来设置列。如果你想实现这种功能,你需要手动完成。您需要在自定义流布局类中处理它 现在问题来了,你们怎么做?如果你不想干扰细胞框架,你可以调整
collectionView:layout:minimumInteritemSpacingForSectionAtIndex:
collectionView:layout:minimumLineSpacingForSectionAtIndex:
另一种方法是提供您自己的单元格位置。通过重写以下两个方法,在布局形成期间将调用这两个方法
- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path
UICollectionViewLayoutAttribute是一个类,它将处理单元格位置、帧、Zindex等我在我的
UICollectionViewController
上实现的UICollectionViewDelegateFlowLayout
,并覆盖负责确定单元格大小的方法。然后,我计算屏幕宽度,并将其与我的列要求分开。例如,我希望每个屏幕大小有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;
}
更新为Swift 3:
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)")
}
}
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()
}
}
我更喜欢对特定的列号和行号使用自定义布局,而不是流布局。因为:
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)")
}
}
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()
}
}
自定义布局:
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)")
}
}
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()
}
}
使用ViewController中的CollectionView:
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)")
}
}
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强>
关于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)
}
这允许单元格之间存在任何间距。它假定一个名为
numberOfItemsPerRow
的Int
成员变量,并且所有单元格都是正方形,大小相同。正如jhilgert00的回答中所指出的,我们还必须对方向的变化做出反应,但现在使用视图willTransitionOnToSize
,因为willRotateToInterfaceOrientation
被贬低了。如果您懒得使用委托
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或更高版本的工作代码,以具有两列布局:
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”更改为所需的列数。使用Swift 5和iOS 12.3,您可以使用以下4实现之一来设置
UICollectionView
中每行的项目数,同时管理插入和大小更改(包括旋转)
#1.子类化
UICollectionViewFlowLayout
并使用UICollectionViewFlowLayout
的属性
ColumnFlowLayout.swift:
CollectionViewController.swift:
#2.使用UICollectionViewFlowLayout的方法
#3.使用UICollectionViewDelegateFlowLayout的方法
#4.子类化
UICollectionViewFlowLayout
并使用UICollectionViewFlowLayout
的属性
CollectionViewController.swift:
FlowLayout.swift:
完美的解决方案是 使用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;}
swift3.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)
}
我只是想在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)
...
}
extension MyCollectionController : UICollectionViewDelegateFlowLayout
然后,我将cellWidth和边距值应用于流布局,如下所示:
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)
...
}
extension MyCollectionController : UICollectionViewDelegateFlowLayout
{
功能集合
#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);
}
let margin: CGFloat = 10
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)
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)
}
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)
}