首页 文章

UICollectionView刷新问题

提问于
浏览
1

使用 UICollectionView 我将 Label 添加到单元格作为 subView ,滚动方向设置为水平 . 在 Label 里面,我添加了一个背景为图像的按钮 . 出于一些奇怪的原因,如果我在一个方向上滚动视图然后返回按钮图像似乎要么留下按钮右侧的残余 . 无论是那个还是他们是在初始按钮下稍微向右移动的另一个按钮 . 我已经意识到我越往右边移动按钮就越多 . 任何援助将不胜感激

如果标签较短,似乎不会出现此问题

enter image description here

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

我已经尝试仅使用按钮和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
}

另一个有趣的特点是我从奇数编号标签中删除了按钮,发现当我执行操作以解决问题时,所有标签上都会出现按钮

2 回答

  • 0

    这看起来像您的单元格被重用,它们显示旧单元格的视图 .

    当您调用 dequeueReusableCellWithReuseIdentifier 时,该方法返回一个在UICollectionView中不再可见的单元格,但它不包含内容 .

    假设您有单元格A,B和C可见,您可以将子视图添加到所有单元格(使用 cell.contentView.addSubview(cellItem) ) . 当您滚动直到单元格A不再可见,并且您调用 dequeueReusableCellWithReuseIdentifier 以获取新单元格(称为D)时,您'll reuse cell A, so it'将具有您之前添加到单元格A的子视图,以及您现在添加到单元格D的子视图 .

    要摆脱这种情况,您有两种选择:

    • 如果您使用的是自定义 UICollectionViewCell ,则应覆盖 prepareForReuse 方法 . 在那里你应该删除所有contentView的子视图 .

    • 如果您使用的是 UICollectionViewCell ,则应在调用 cell.contentView.addSubview(cellItem) 之前删除所有contentView的子视图

    如果要查看是否多次向重用单元格添加按钮,可以重现该问题并使用“视图层次结构”检查器:

    enter image description here

    我创建了一个小项目来说明"dirty"细胞的问题:https://github.com/lucaslt89/DirtyUICollectionViewCellsExample

  • 2

    在我的例子中,我在单元格的 init 方法中创建了视图层次结构 .

    当缓慢滚动时,细胞和多线标签将完美呈现 . 但是,当滚动太快时,标签将具有重复使用的单元格标签的大小,因此看起来非常糟糕 .

    我正确地设置了 preferredMaxLayoutWidth ,但是细胞在快速滚动时会出现问题 .

    我的问题通过在 prepareForReuse 内调用 setNeedsLayout 来解决:

    override func prepareForReuse() {
        setNeedsLayout()
        super.prepareForReuse()
    }
    

相关问题