当单元格具有动态宽度时,CollectionView 中的间距不正确?
Posted
技术标签:
【中文标题】当单元格具有动态宽度时,CollectionView 中的间距不正确?【英文标题】:Spacing is not correct in CollectionView when cell having dynamic width? 【发布时间】:2018-05-25 12:09:22 【问题描述】:我想实现一个TokenView(芯片视图)风格的视图。为此,我在 UITableViewCell 内使用集合视图,CollectionView 有自定义单元格。在自定义单元格内有UILabel
。现在单元格的宽度取决于UILabel
的内容。
下面是自定义 UITableViewCell Cell 的代码
import UIKit
class LanguageTableViewCell: UITableViewCell,UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout
var arr:[String] = ["English","Intermediate","English","Intermediate","English","Intermediate","English","Intermediate","English","Intermediate","English","Intermediate","English","Intermediate","English","Intermediate","English","Intermediate","English","Intermediate","English","Intermediate"]
@IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib()
super.awakeFromNib()
collectionView.dataSource = self
collectionView.delegate = self
let layout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
layout.scrollDirection = .vertical
self.collectionView.collectionViewLayout = layout
// Initialization code
override func setSelected(_ selected: Bool, animated: Bool)
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
return arr.count
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "LanguageCollectionViewCell", for: indexPath) as! LanguageCollectionViewCell
cell.setValue(lang: arr[indexPath.row],indexPath:indexPath)
return cell
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
let string = arr[indexPath.row]
let width = (string.count * 10)
return CGSize(width:width, height: 30)
UICollectionViewCell
的类
typealias Parameters = [String:Any]
import UIKit
class LanguageCollectionViewCell: UICollectionViewCell
@IBOutlet weak var languageLabel: UILabel!
override func layoutSubviews()
super.layoutSubviews()
func setValue(lang:String ,indexPath:IndexPath)
if indexPath.row % 2 == 0
languageLabel.backgroundColor = UIColor.gray
else
languageLabel.backgroundColor = UIColor.yellow
self.languageLabel.text = lang
【问题讨论】:
见raywenderlich.com/164608/… github.com/keighl/KTCenterFlowLayout 你在用stackView吗? 【参考方案1】:在您的 UITableViewCell Cell
中实现这一点
-
子类化
UICollectionViewFlowLayout
添加这样的实现:
解决方案是减少单元格间距/对齐 UICollectionView 单元格布局。非常简单和快速的性能。基于Olloqui给出的例子
类 CustomViewFlowLayout
class CustomViewFlowLayout: UICollectionViewFlowLayout
let cellSpacing:CGFloat = 4
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]?
self.minimumLineSpacing = 4.0
self.sectionInset = UIEdgeInsets(top: 10, left: 8, bottom: 10, right: 6)
let attributes = super.layoutAttributesForElements(in: rect)
var leftMargin = sectionInset.left
var maxY: CGFloat = -1.0
attributes?.forEach layoutAttribute in
if layoutAttribute.frame.origin.y >= maxY
leftMargin = sectionInset.left
layoutAttribute.frame.origin.x = leftMargin
leftMargin += layoutAttribute.frame.width + cellSpacing
maxY = max(layoutAttribute.frame.maxY , maxY)
return attributes
其中 cellSpacing 可以设置为您喜欢的任何值。这个技巧保证单元格之间的空间将完全等于 cellSpacing。
UITableViewCell Cell/CollectionViewController 的实现。
import UIKit
class ViewController: UIViewController , UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
@IBOutlet weak var collectionView: UICollectionView!
var arr:[String] = ["English","Intermediate","English","English","arr","UICollectionViewFlowLayoutFlowFlowFlow","English","UICollectionViewDelegate","English","Intermediate","UIViewController","viewDidLoad","Intermediate","String","Intermediate","arr","Intermediate","UIKit","Intermediate","English","columnLayout","English","languageLabel"]
let columnLayout = CustomViewFlowLayout()
override func viewDidLoad()
super.viewDidLoad()
collectionView.collectionViewLayout = columnLayout
collectionView.contentInsetAdjustmentBehavior = .always
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
return arr.count
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "chip", for: indexPath) as! LanguageCollectionViewCell
cell.languageLabel.text = arr[indexPath.row]
return cell
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
let string = arr[indexPath.row]
// your label font.
let font = UIFont.systemFont(ofSize: 16)
let fontAttribute = [NSAttributedStringKey.font: font]
// to get the exact width for label according to ur label font and Text.
let size = string.size(withAttributes: fontAttribute)
// some extraSpace give if like so.
let extraSpace : CGFloat = 8.0
let width = size.width + extraSpace
return CGSize(width:width, height: 30)
UICollectionViewCell
的类
class LanguageCollectionViewCell: UICollectionViewCell
@IBOutlet weak var languageLabel: UILabel!
【讨论】:
【参考方案2】:我也用过一个吊舱
pod 'AlignedCollectionViewFlowLayout'
在我使用UICollectionView
的课堂上,
import AlignedCollectionViewFlowLayout
并配置collectionViewLayout如下
if let fl = myCollection.collectionViewLayout as? AlignedCollectionViewFlowLayout
fl.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize
fl.horizontalAlignment = .left
fl.verticalAlignment = .top
请注意,您可以使用此设置左/右和上/下对齐 荚!它对我来说就像一个魅力
我还确保将preferredMaxLayoutWidth
添加到UICollectionViewCell
的标签中,以便修复可能出现的错误之一(即单元格的宽度不能大于屏幕尺寸)
class MyCollectionViewCell: UICollectionViewCell
override func awakeFromNib()
super.awakeFromNib()
// Initialization code
myLabel.preferredMaxLayoutWidth = UIScreen.main.bounds.size.width * 0.8
我的收藏结果如下:
【讨论】:
【参考方案3】:1-实现UICollectionViewDelegateFlowLayout协议,
添加以下代码:
var itemsPerRow:CGFloat = 3
让 sectionInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
然后添加委托方法来确定间距,如下所示;
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize
let paddingSpace = sectionInsets.left * (itemsPerRow + 1)
let availableWidth = view.frame.width - paddingSpace
let widthPerItem = availableWidth / itemsPerRow
return CGSize(width: widthPerItem, height: widthPerItem)
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAt section: Int) -> UIEdgeInsets
return sectionInsets
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat
return 10
【讨论】:
【参考方案4】:你可以试试
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
let lb = UILabel()
lb.text = arr[indexPath.row]
lb.font = UIFont.init(name: "System", size: 17)
lb.sizeToFit()
return CGSize(width:lb.frame.size.width, height: 30 )
//
或者设置这个
layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize
并为单元格提供基于 0 的前导、尾随、顶部和底部约束
注意:在这两种情况下,您都必须删除方法sizeForItemAt
的实现
【讨论】:
以上是关于当单元格具有动态宽度时,CollectionView 中的间距不正确?的主要内容,如果未能解决你的问题,请参考以下文章