Layout CollectionView动态单元格高度
我正在尝试创建一个集合视图,其中单元格显示长度可变的字符串 Im使用此功能设置单元格布局:Layout CollectionView动态单元格高度,layout,swift,height,uicollectionview,Layout,Swift,Height,Uicollectionview,我正在尝试创建一个集合视图,其中单元格显示长度可变的字符串 Im使用此功能设置单元格布局: func collectionView(collectionView : UICollectionView,layout collectionViewLayout:UICollectionViewLayout,sizeForItemAtIndexPath indexPath:NSIndexPath) -> CGSize { var cellSize:CGSize = CGS
func collectionView(collectionView : UICollectionView,layout collectionViewLayout:UICollectionViewLayout,sizeForItemAtIndexPath indexPath:NSIndexPath) -> CGSize
{
var cellSize:CGSize = CGSizeMake(self.whyCollectionView.frame.width, 86)
return cellSize
}
我想做的是根据我的cell.labelString.utf16Count
长度操作cellSize.height
。
基本逻辑是
if((cell.labelString.text) > 70){
cellSize.height = x
}
else{
cellSize.height = y
}
但是,我无法检索总是返回nil的单元格标签字符串长度。(我想它还没有加载
为了更好地理解,以下是完整的代码:
// WhyCell section
var whyData:NSMutableArray! = NSMutableArray()
var textLength:Int!
@IBOutlet weak var whyCollectionView: UICollectionView!
//Loading data
@IBAction func loadData() {
whyData.removeAllObjects()
var findWhyData:PFQuery = PFQuery(className: "PlacesWhy")
findWhyData.whereKey("placeName", equalTo: placeName)
findWhyData.findObjectsInBackgroundWithBlock({
(objects:[AnyObject]!,error:NSError!)->Void in
if (error == nil) {
for object in objects {
self.whyData.addObject(object)
}
let array:NSArray = self.whyData.reverseObjectEnumerator().allObjects
self.whyData = array.mutableCopy() as NSMutableArray
self.whyCollectionView.reloadData()
println("loadData completed. datacount is \(self.whyData.count)")
}
})
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.loadData()
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return whyData.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell:whyCollectionViewCell = whyCollectionView.dequeueReusableCellWithReuseIdentifier("whyCell", forIndexPath: indexPath) as whyCollectionViewCell
// Loading content from NSMutableArray to cell
let therew:PFObject = self.whyData.objectAtIndex(indexPath.row) as PFObject
cell.userWhy.text = therew.objectForKey("why") as String!
textLength = (therew.objectForKey("why") as String!).utf16Count
self.whyCollectionView.layoutSubviews()
// Displaying user information
var whatUser:PFQuery = PFUser.query()
whatUser.whereKey("objectId", equalTo: therew.objectForKey("reasonGivenBy").objectId)
whatUser.findObjectsInBackgroundWithBlock({
(objects: [AnyObject]!, error: NSError!)->Void in
if !(error != nil) {
if let user:PFUser = (objects as NSArray).lastObject as? PFUser {
cell.userName.text = user.username
// TODO Display avatar
}
}
})
return cell
}
func collectionView(collectionView : UICollectionView,layout collectionViewLayout:UICollectionViewLayout,sizeForItemAtIndexPath indexPath:NSIndexPath) -> CGSize
{
var cellSize:CGSize = CGSizeMake(self.whyCollectionView.frame.width, 86)
return cellSize
}
您可以在
CellForItemIndexPath
函数中动态设置单元格的框架,因此,如果不考虑SizeForItemIndexPath
函数,您可以基于标签自定义高度。通过自定义大小,您可能需要查看集合视图布局流程,但希望这能为您指明方向t方向。它可能看起来像这样:
class CollectionViewController: UICollectionViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var array = ["a","as","asd","asdf","asdfg","asdfgh","asdfghjk","asdfghjklas","asdfghjkl","asdghjklkjhgfdsa"]
var heights = [10.0,20.0,30.0,40.0,50.0,60.0,70.0,80.0,90.0,100.0,110.0] as [CGFloat]
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return array.count
}
override func collectionView(collectionView: UICollectionView,
cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CellID", forIndexPath: indexPath) as Cell
cell.textLabel.text = array[indexPath.row]
cell.textLabel.sizeToFit()
// Customize cell height
cell.frame = CGRectMake(cell.frame.origin.x, cell.frame.origin.y, cell.frame.size.width, heights[indexPath.row])
return cell
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake(64, 64)
}
}
这就产生了这样的动态高度
虽然上面的答案可能会解决您的问题,但它建立了一种相当粗糙的分配每个单元格高度的方法。您被迫根据一些估计值对每个单元格高度进行硬编码。处理此问题的更好方法是在collectionview的
SizeFormiteIndeXPath
委托方法中设置每个单元格的高度
我将引导您完成下面有关如何执行此操作的步骤
步骤1:使类扩展UICollectionViewDelegateFlowLayout
步骤2:创建一个函数来估计文本的大小:这个方法将返回一个适合字符串的高度值
private func estimateFrameForText(text: String) -> CGRect {
//we make the height arbitrarily large so we don't undershoot height in calculation
let height: CGFloat = <arbitrarilyLargeValue>
let size = CGSize(width: yourDesiredWidth, height: height)
let options = NSStringDrawingOptions.UsesFontLeading.union(.UsesLineFragmentOrigin)
let attributes = [NSFontAttributeName: UIFont.systemFontOfSize(18, weight: UIFontWeightLight)]
return NSString(string: text).boundingRectWithSize(size, options: options, attributes: attributes, context: nil)
}
private func estimateFrameForText(文本:字符串)->CGRect{
//我们将高度设为任意大,这样在计算中就不会忽略高度
让高:CGFloat=
let size=CGSize(宽度:您想要的宽度,高度:高度)
let options=NSStringDrawingOptions.UseSFuntleding.union(.UsesLineFragmentOrigin)
let attributes=[NSFontAttributeName:UIFont.systemFontOfSize(18,权重:UIFontWeightLight)]
返回NSString(字符串:文本)。boundingRectWithSize(大小、选项:选项、属性:属性、上下文:nil)
}
步骤3:使用或覆盖以下委托方法:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
var height: CGFloat = <someArbitraryValue>
//we are just measuring height so we add a padding constant to give the label some room to breathe!
var padding: CGFloat = <someArbitraryPaddingValue>
//estimate each cell's height
if let text = array?[indexPath.item].text {
height = estimateFrameForText(text).height + padding
}
return CGSize(width: yourDesiredWidth, height: height)
}
func collectionView(collectionView:UICollectionView,layout collectionViewLayout:UICollectionViewLayout,sizeFormiteIndepath indepath:nsindepath)->CGSize{
变量高度:CGFloat=
//我们只是测量高度,所以我们添加了一个填充常数,给标签一些呼吸的空间!
变量填充:CGFloat=
//估计每个单元的高度
如果let text=array?[indexPath.item].text{
高度=估计FrameforText(文本)。高度+填充
}
返回CGSize(宽度:yourDesiredWidth,高度:height)
}
在Swift 3中,使用以下方法:
private func updateCollectionViewLayout(with size: CGSize) {
var margin : CGFloat = 0;
if isIPad {
margin = 10
}
else{
margin = 6
/* if UIDevice.current.type == .iPhone6plus || UIDevice.current.type == .iPhone6Splus || UIDevice.current.type == .simulator{
margin = 10
}
*/
}
if let layout = menuCollectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.itemSize = CGSize(width:(self.view.frame.width/2)-margin, height:((self.view.frame.height-64)/4)-3)
layout.invalidateLayout()
}
}
太棒了,我探索了几种解决此问题的方法,但我没有考虑在cellForItemAtIndexPath中执行此操作。感谢您提供的提示,我会让您知道!好的,似乎我可以使用您的方法调整高度,但现在我的问题变成了行间距。我有一些不需要的重要空间。我的所有设置都设置为零w我在我的故事板高度[indexPath.row]是服务器数据对象。你能告诉我吗。你不应该计算单元格的高度而不是将其存储在数组中吗?你在哪里调用此方法?我在“行数”方法中调用此方法,以便它每次都为行创建高度。此外,你可以在“方向更改”方法中调用它并调用重新加载集合view.Method.boundingRectWithSize似乎无法与swift 3和ios 10配合使用。计算在不同的屏幕尺寸上是不同的,更重要的是,它计算的文本高度太高了。非常感谢。我一直在努力解决这个问题,但我看到的示例中没有一个足够清楚地指出需要扩展UICollectionViewDelegateFlowLayout。没问题,很高兴你已经弄明白了。