设置集合视图单元格的动态宽度时出现问题
issue while set dynamic width of collection view cell
我正在尝试动态设置集合视图单元格的宽度。最初它没有按预期呈现。但是当我点击单元格时,它会根据需要进行调整。这是我写的代码:
代码
import UIKit
class ViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource {
@IBOutlet weak var collView: UICollectionView!
var tasksArray = ["To Do", "SHOPPING","WORK"]
var selectedIndex = Int()
override func viewDidLoad() {
super.viewDidLoad()
let layout = collView?.collectionViewLayout as! UICollectionViewFlowLayout
layout.itemSize = UICollectionViewFlowLayout.automaticSize
layout.estimatedItemSize = CGSize(width: 93, height: 40)
// Do any additional setup after loading the view, typically from a nib.
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return tasksArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
cell.lblName.text = tasksArray[indexPath.row]
if selectedIndex == indexPath.row
{
cell.backgroundColor = UIColor.lightGray
}
else
{
cell.backgroundColor = UIColor.white
}
cell.layer.borderWidth = 1
cell.layer.cornerRadius = cell.frame.height / 2
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedIndex = indexPath.row
self.collView.reloadData()
}
}
这里我附上两张点击前和点击后的图片,方便大家理解
[![这是我点击前的图像
on cell]2]2
所以请告诉我我的代码有什么问题
我找到了 swift 4.2
的小技巧
对于动态宽度和固定高度:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let label = UILabel(frame: CGRect.zero)
label.text = textArray[indexPath.item]
label.sizeToFit()
return CGSize(width: label.frame.width, height: 32)
}
在您的 CollectionViewCell
覆盖 preferredLayoutAttributesFitting
函数中,单元格可以在此处指示其首选属性,包括我们使用自动布局计算的大小。
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
setNeedsLayout()
layoutIfNeeded()
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
var frame = layoutAttributes.frame
frame.size.width = ceil(size.width)
layoutAttributes.frame = frame
return layoutAttributes
}
很明显,您必须使用 sizeForItemAt
流布局委托才能传递动态宽度。但棘手的部分是根据文本计算单元格的宽度。如果你有字体,你实际上可以计算文本的宽度。
让我们介绍几个扩展,这将在整个过程中帮助我们
StringExtensions.swift
extension String {
public func width(withConstrainedHeight height: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
let boundingBox = self.boundingRect(with: constraintRect,
options: .usesLineFragmentOrigin,
attributes: [.font: font], context: nil)
return ceil(boundingBox.width)
}
}
这个方法让我们知道字符串的宽度,如果我给它提供高度和字体的话。然后在sizeForItem
里面使用如下
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let height = 40
let text = YOUR_TEXT
let width = text.width(withConstrainedHeight: height, font: Font.regular.withSize(.extraSmall)) + EXTRA_SPACES_FOR_LEFT_RIGHT_PADDING
return CGSize(width: width, height: height)
}
我正在尝试动态设置集合视图单元格的宽度。最初它没有按预期呈现。但是当我点击单元格时,它会根据需要进行调整。这是我写的代码:
代码
import UIKit
class ViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource {
@IBOutlet weak var collView: UICollectionView!
var tasksArray = ["To Do", "SHOPPING","WORK"]
var selectedIndex = Int()
override func viewDidLoad() {
super.viewDidLoad()
let layout = collView?.collectionViewLayout as! UICollectionViewFlowLayout
layout.itemSize = UICollectionViewFlowLayout.automaticSize
layout.estimatedItemSize = CGSize(width: 93, height: 40)
// Do any additional setup after loading the view, typically from a nib.
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return tasksArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
cell.lblName.text = tasksArray[indexPath.row]
if selectedIndex == indexPath.row
{
cell.backgroundColor = UIColor.lightGray
}
else
{
cell.backgroundColor = UIColor.white
}
cell.layer.borderWidth = 1
cell.layer.cornerRadius = cell.frame.height / 2
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedIndex = indexPath.row
self.collView.reloadData()
}
}
这里我附上两张点击前和点击后的图片,方便大家理解
[![这是我点击前的图像
所以请告诉我我的代码有什么问题
我找到了 swift 4.2
的小技巧对于动态宽度和固定高度:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let label = UILabel(frame: CGRect.zero)
label.text = textArray[indexPath.item]
label.sizeToFit()
return CGSize(width: label.frame.width, height: 32)
}
在您的 CollectionViewCell
覆盖 preferredLayoutAttributesFitting
函数中,单元格可以在此处指示其首选属性,包括我们使用自动布局计算的大小。
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
setNeedsLayout()
layoutIfNeeded()
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
var frame = layoutAttributes.frame
frame.size.width = ceil(size.width)
layoutAttributes.frame = frame
return layoutAttributes
}
很明显,您必须使用 sizeForItemAt
流布局委托才能传递动态宽度。但棘手的部分是根据文本计算单元格的宽度。如果你有字体,你实际上可以计算文本的宽度。
让我们介绍几个扩展,这将在整个过程中帮助我们
StringExtensions.swift
extension String {
public func width(withConstrainedHeight height: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
let boundingBox = self.boundingRect(with: constraintRect,
options: .usesLineFragmentOrigin,
attributes: [.font: font], context: nil)
return ceil(boundingBox.width)
}
}
这个方法让我们知道字符串的宽度,如果我给它提供高度和字体的话。然后在sizeForItem
里面使用如下
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let height = 40
let text = YOUR_TEXT
let width = text.width(withConstrainedHeight: height, font: Font.regular.withSize(.extraSmall)) + EXTRA_SPACES_FOR_LEFT_RIGHT_PADDING
return CGSize(width: width, height: height)
}