UICollectionView 刷新问题
UICollectionView Refresh Issue
使用 UICollectionView
我将 Label
作为 subView
添加到单元格,滚动方向设置为水平。在 Label
中,我添加了一个背景为图像的按钮。出于某种奇怪的原因,如果我向一个方向滚动视图然后返回,按钮图像似乎要么在按钮右侧留下了残余物。那个或它们是另一个按钮,在初始按钮下方稍微向右移动。我意识到我对按钮的操作越多,它们就会向右移动得越远。如有任何帮助,我们将不胜感激
如果标签较短,问题似乎不会发生
var padding = String(count: 2, repeatedValue: (" " as Character))
let newLabel = UILabel(frame: CGRectZero)
newLabel.autoresizingMask = .FlexibleHeight
newLabel.backgroundColor = UIColor(red: 56/255, green: 143/255, blue: 212/255, alpha: 1)
newLabel.text = "\(padding)\(title)\(padding)"
newLabel.textColor = UIColor.whiteColor()
let fontName: CFStringRef = "Superclarendon-Regular"
newLabel.font = CTFontCreateWithName(fontName, 15, nil)
newLabel.adjustsFontSizeToFitWidth = true
newLabel.clipsToBounds = true
newLabel.layer.cornerRadius = 4
//Fit TO Text
newLabel.numberOfLines = 1
newLabel.sizeToFit()
//Add Button
if let image = UIImage(named: "Nav_Button_X"){//?//.CGImage
let button = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var imageWidth = image.size.width
var imageHeight = image.size.height
//Resize label for button
var oldLabelFrame = newLabel.frame
var buttonHeight = self.frame.height - self.sectionInsets.top - self.sectionInsets.bottom
var buttonWidth = newLabel.frame.width + imageWidth
//newLabel.frame = CGRect(x: oldLabelFrame.origin.x, y: oldLabelFrame.origin.y, width: oldLabelFrame.width, height: bh)
newLabel.frame.size = CGSize(width: buttonWidth, height: buttonHeight)
button.frame = CGRectMake(newLabel.frame.width - imageWidth, 0, imageWidth, newLabel.frame.height)
button.setBackgroundImage(image, forState: UIControlState.Normal)
newLabel.addSubview(button)
}
return newLabel
}
编辑:
我试过仅使用一个按钮和 NSMutableAttributedString 来重新创建视图,这可能是也可能不是更好的解决方案耸耸肩,问题仍然存在,所以它可能不是我如何构建按钮的问题。有什么建议吗?
我像这样子类化并设置 UICollectionView
let flowLayout:UICollectionViewFlowLayout = UICollectionViewFlowLayout();
flowLayout.scrollDirection = UICollectionViewScrollDirection.Horizontal
super.init(frame: CGRectMake(0, 0, width, height), collectionViewLayout: flowLayout);
self.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier);
self.autoresizingMask = UIViewAutoresizing.FlexibleWidth
self.backgroundColor = UIColor.whiteColor()
self.bounces = true
self.layer.cornerRadius = 5
self.scrollEnabled = true
self.delegate = self;
self.dataSource = self;
self.backgroundColor = UIColor.whiteColor();
和
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell:UICollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! UICollectionViewCell;
cell.backgroundColor = UIColor.clearColor();
let cellItem = subCategories[indexPath.row]
cell.contentView.addSubview(cellItem)
// Configure the cell
return cell
}
另一个有趣的特点是,我从奇数标签中删除了按钮,发现当我执行操作以解决问题时,按钮出现在所有标签上
这看起来您的单元格正在被重复使用,它们显示旧单元格的视图。
当您调用 dequeueReusableCellWithReuseIdentifier
时,方法 returns 一个单元格在 UICollectionView 中不再可见,但不会清除其内容。
假设您有单元格 A、B 和 C 可见,您将子视图添加到所有单元格(使用 cell.contentView.addSubview(cellItem)
)。当您滚动直到单元格 A 不再可见,并且您调用 dequeueReusableCellWithReuseIdentifier
来获取一个新单元格(称为 D)时,您将重复使用单元格 A,因此它将具有您之前添加到单元格的子视图A,以及您现在添加到单元格 D 的子视图。
要摆脱这种情况,您有两种选择:
- 如果您使用的是自定义
UICollectionViewCell
,您应该覆盖 prepareForReuse
方法。在那里你应该删除所有 contentView 的子视图。
- 如果您使用的是
UICollectionViewCell
,您应该在调用 cell.contentView.addSubview(cellItem)
之前删除所有 contentView 的子视图
如果您想查看是否将按钮多次添加到重复使用的单元格,您可以重现该问题并使用视图层次结构检查器:
我创建了一个小项目来说明 "dirty" 个单元格的问题:https://github.com/lucaslt89/DirtyUICollectionViewCellsExample
就我而言,我在单元格的 init
方法中创建了视图层次结构。
缓慢滚动时,单元格和多行标签会完美显示。但是,当滚动太快时,标签的大小将与重复使用的单元格标签的大小相同,因此显得非常糟糕。
我设置 preferredMaxLayoutWidth
正确,但单元格在快速滚动时会出现问题。
我的问题通过在 prepareForReuse
:
中调用 setNeedsLayout
解决了
override func prepareForReuse() {
setNeedsLayout()
super.prepareForReuse()
}
使用 UICollectionView
我将 Label
作为 subView
添加到单元格,滚动方向设置为水平。在 Label
中,我添加了一个背景为图像的按钮。出于某种奇怪的原因,如果我向一个方向滚动视图然后返回,按钮图像似乎要么在按钮右侧留下了残余物。那个或它们是另一个按钮,在初始按钮下方稍微向右移动。我意识到我对按钮的操作越多,它们就会向右移动得越远。如有任何帮助,我们将不胜感激
如果标签较短,问题似乎不会发生
var padding = String(count: 2, repeatedValue: (" " as Character))
let newLabel = UILabel(frame: CGRectZero)
newLabel.autoresizingMask = .FlexibleHeight
newLabel.backgroundColor = UIColor(red: 56/255, green: 143/255, blue: 212/255, alpha: 1)
newLabel.text = "\(padding)\(title)\(padding)"
newLabel.textColor = UIColor.whiteColor()
let fontName: CFStringRef = "Superclarendon-Regular"
newLabel.font = CTFontCreateWithName(fontName, 15, nil)
newLabel.adjustsFontSizeToFitWidth = true
newLabel.clipsToBounds = true
newLabel.layer.cornerRadius = 4
//Fit TO Text
newLabel.numberOfLines = 1
newLabel.sizeToFit()
//Add Button
if let image = UIImage(named: "Nav_Button_X"){//?//.CGImage
let button = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var imageWidth = image.size.width
var imageHeight = image.size.height
//Resize label for button
var oldLabelFrame = newLabel.frame
var buttonHeight = self.frame.height - self.sectionInsets.top - self.sectionInsets.bottom
var buttonWidth = newLabel.frame.width + imageWidth
//newLabel.frame = CGRect(x: oldLabelFrame.origin.x, y: oldLabelFrame.origin.y, width: oldLabelFrame.width, height: bh)
newLabel.frame.size = CGSize(width: buttonWidth, height: buttonHeight)
button.frame = CGRectMake(newLabel.frame.width - imageWidth, 0, imageWidth, newLabel.frame.height)
button.setBackgroundImage(image, forState: UIControlState.Normal)
newLabel.addSubview(button)
}
return newLabel
}
编辑:
我试过仅使用一个按钮和 NSMutableAttributedString 来重新创建视图,这可能是也可能不是更好的解决方案耸耸肩,问题仍然存在,所以它可能不是我如何构建按钮的问题。有什么建议吗?
我像这样子类化并设置 UICollectionView
let flowLayout:UICollectionViewFlowLayout = UICollectionViewFlowLayout();
flowLayout.scrollDirection = UICollectionViewScrollDirection.Horizontal
super.init(frame: CGRectMake(0, 0, width, height), collectionViewLayout: flowLayout);
self.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier);
self.autoresizingMask = UIViewAutoresizing.FlexibleWidth
self.backgroundColor = UIColor.whiteColor()
self.bounces = true
self.layer.cornerRadius = 5
self.scrollEnabled = true
self.delegate = self;
self.dataSource = self;
self.backgroundColor = UIColor.whiteColor();
和
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell:UICollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! UICollectionViewCell;
cell.backgroundColor = UIColor.clearColor();
let cellItem = subCategories[indexPath.row]
cell.contentView.addSubview(cellItem)
// Configure the cell
return cell
}
另一个有趣的特点是,我从奇数标签中删除了按钮,发现当我执行操作以解决问题时,按钮出现在所有标签上
这看起来您的单元格正在被重复使用,它们显示旧单元格的视图。
当您调用 dequeueReusableCellWithReuseIdentifier
时,方法 returns 一个单元格在 UICollectionView 中不再可见,但不会清除其内容。
假设您有单元格 A、B 和 C 可见,您将子视图添加到所有单元格(使用 cell.contentView.addSubview(cellItem)
)。当您滚动直到单元格 A 不再可见,并且您调用 dequeueReusableCellWithReuseIdentifier
来获取一个新单元格(称为 D)时,您将重复使用单元格 A,因此它将具有您之前添加到单元格的子视图A,以及您现在添加到单元格 D 的子视图。
要摆脱这种情况,您有两种选择:
- 如果您使用的是自定义
UICollectionViewCell
,您应该覆盖prepareForReuse
方法。在那里你应该删除所有 contentView 的子视图。 - 如果您使用的是
UICollectionViewCell
,您应该在调用cell.contentView.addSubview(cellItem)
之前删除所有 contentView 的子视图
如果您想查看是否将按钮多次添加到重复使用的单元格,您可以重现该问题并使用视图层次结构检查器:
我创建了一个小项目来说明 "dirty" 个单元格的问题:https://github.com/lucaslt89/DirtyUICollectionViewCellsExample
就我而言,我在单元格的 init
方法中创建了视图层次结构。
缓慢滚动时,单元格和多行标签会完美显示。但是,当滚动太快时,标签的大小将与重复使用的单元格标签的大小相同,因此显得非常糟糕。
我设置 preferredMaxLayoutWidth
正确,但单元格在快速滚动时会出现问题。
我的问题通过在 prepareForReuse
:
setNeedsLayout
解决了
override func prepareForReuse() {
setNeedsLayout()
super.prepareForReuse()
}