Reputation: 2199
Using UICollectionView
I add a Label
to a cell as a subView
with the scroll direction set to horizontal. Inside the Label
I add a button whose background is an image. For some odd reason if I scroll the view in one direction and then come back the buttons image seems to either have left remnants to the right of the button. Either that or their is another button slightly shifted to the right under the initial buttons. I have realized the more I played around with the buttons the further right they shift. Any assistance would be appreciated
The issue does not seem to occur if the label is shorter
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
}
EDIT:
I have tried recreating the view using only a button and NSMutableAttributedString for styling, which may or may not be a better solution shrugs, and the issue persists so it may not be an issue of how I construct the button. Are there suggestions?
I subclass and set up the UICollectionView like so
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();
and
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
}
Another interesting trait is that I removed the button from odd numbered labels and found that when I perform the action to get the issue the buttons appear on all of the labels
Upvotes: 1
Views: 3467
Reputation: 3968
In my case, I created the view hierarchy in the init
method of the cell.
When scrolling slowly, the cells along with the multiline labels would appear perfectly. However, when scrolling too quickly, labels would have the size of the reused cell's label, thus appearing very bad.
I was setting preferredMaxLayoutWidth
correctly, but nevertheless the cells would have issues on fast scrolling.
My problem was solved by calling setNeedsLayout
inside prepareForReuse
:
override func prepareForReuse() {
setNeedsLayout()
super.prepareForReuse()
}
Upvotes: 0
Reputation: 2451
This looks like your cells are being reused and they show views from old cells.
When you call dequeueReusableCellWithReuseIdentifier
, the method returns a cell that is not visible anymore in the UICollectionView, but it doesn't clear it's content.
Let's say you have cells A, B and C visible, you add subviews to all of them (with cell.contentView.addSubview(cellItem)
). When you scroll until cell A isn't visible anymore, and you call dequeueReusableCellWithReuseIdentifier
to get a new cell (call it D), you'll reuse cell A, so it'll have the subviews you added before to cell A, and the subviews you add now to cell D.
To get rid of this, you have two options:
UICollectionViewCell
, you should override prepareForReuse
method. There you should remove all contentView's subviews.UICollectionViewCell
, you should remove all contentView's subviews before calling cell.contentView.addSubview(cellItem)
If you want to see if you're adding the button multiple times to reused cells, you can reproduce the issue and use the View Hierarchy inspector:
I created a small project to illustrate the issue of "dirty" cells: https://github.com/lucaslt89/DirtyUICollectionViewCellsExample
Upvotes: 2