快速滚动后在 UICollectionView 中保留按钮内容

Posted

技术标签:

【中文标题】快速滚动后在 UICollectionView 中保留按钮内容【英文标题】:Retaining button content in UICollectionView after scrolling with swift 【发布时间】:2015-03-06 02:13:43 【问题描述】:

我正在尝试制作一个具有无限滚动按钮的 UICollectionView,并且该按钮的背景是根据对服务器的 http 请求的结果填充的。

let reuseIdentifier = "Cell"
let screenSize: CGRect = UIScreen.mainScreen().bounds
let screenWidth = screenSize.width
let screenHeight = screenSize.height

let categoryApiUrl = "url"
let categoryImageField = "field"

class BrowseViewController: UICollectionViewController, UICollectionViewDataSource, UICollectionViewDelegate 

var categoryImgUrl:[String] = []
var buttonList:[UIButton] = []

func setupView()

    self.title = "Browse"
    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
    layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
    layout.itemSize = CGSize(width: screenWidth/2-15, height: screenHeight/3.5)
    collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
    collectionView!.dataSource = self
    collectionView!.delegate = self
    collectionView!.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
    collectionView!.backgroundColor = UIColor.whiteColor()
    self.view.addSubview(collectionView!)



func setupButton(cell: UICollectionViewCell, cellNumber: Int)

    var button   = UIButton.buttonWithType(UIButtonType.System) as UIButton
    button.frame = CGRectMake(0, 0, screenWidth/2-15, screenHeight/3.5)
    button.backgroundColor = UIColor.orangeColor()
    button.setTitle("Category", forState: UIControlState.Normal)
    button.addTarget(self, action: "btnClicked:", forControlEvents: UIControlEvents.TouchUpInside)
    buttonList.append(button)
    cell.addSubview(button)


override func viewDidLoad()
    super.viewDidLoad()
    let url = NSURL(string: categoryApiUrl)
    let request = NSURLRequest(URL: url!)

    NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) (response, dataValue, error) in

        let json = JSON(data: dataValue)

        for(var i = 0; i < json.count; i++)

            self.categoryImgUrl.append(json[i]["CATEGORY_IMAGE"].stringValue)

            let imageUrl = self.categoryImgUrl[i]
            let url = NSURL(string: imageUrl)
            let data = NSData(contentsOfURL: url!)
            let image = UIImage(data: data!)
            self.buttonList[i].setBackgroundImage(image, forState: .Normal)
        
    

override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int 
    //#warning Incomplete method implementation -- Return the number of sections
    return 1


override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
    //#warning Incomplete method implementation -- Return the number of items in the section
    return 10;


override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as UICollectionViewCell

    let cellNumber = indexPath.row as Int
    setupButton(cell, cellNumber: cellNumber)
    // Configure the cell
    return cell


override func scrollViewDidScroll(scrollView: UIScrollView) 
    let offsetY = scrollView.contentOffset.y
    let contentHeight = scrollView.contentSize.height

    if offsetY > contentHeight - scrollView.frame.size.height 
        numberOfItemsPerSection += 6
        self.collectionView!.reloadData()
    



目前,代码能够从服务器拉取图像并将其填充为按钮的背景图像。

但是,因为我使这个集合视图可滚动。当我向下滚动视图然后向上滚动时,前一个按钮的背景图像会消失。

我做了一些研究,但找不到解决方案。按钮消失的原因是因为 ios 只加载屏幕上可见的单元格。因此,当我向下滚动然后向上滚动时,以前的单元格被视为“新单元格”。因此,其中的背景图像现在消失了。

问题:

有没有人知道如何保留以前的按钮,即使我们向下滚动然后向上滚动?此外,使用我当前的代码,我将图像添加到 http 请求内的按钮上,因为 http 请求始终是最后完成的执行。无论如何要更改代码,以便在加载单元格之前完成 http 请求?

【问题讨论】:

【参考方案1】:

我建议在界面生成器中创建uicollectionview,子类uicollectionviewcell,向collectionview添加一个动态单元格,将其类更改为您子类化的collectionviewcell,在其上放置uibutton,每次创建单元格时,您都会下载图像。

override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as myCollectionViewCell

    let cellNumber = indexPath.row as Int
    //downloadimghere

cell.myButton.setBackgroundImage(downloadedImg, forState: .Normal)
    return cell

这将在每次创建单元格时下载图像。有关更多信息,您应该查看“延迟图像加载”。我认为这是解决您的问题的更好方法。

现在到您的代码,首先您没有使用 buttonList 数组,每次创建单元格时,您都会创建一个新按钮并将其放置在那里,因此您不会重复使用已创建的按钮。如果你解决了这个问题,它可能会像你想要的那样工作。

这是另一个问题,因为collectionview正在重用单元格,每次您创建一个按钮并将其放置在单元格上时,它都会停留在那里,所以基本上现在您是在按钮上创建按钮。因此,如果您希望它正常工作并且单元格上只有一个按钮,则需要在创建之前从单元格中删除上一个按钮,您可以在 cellForItemAtIndexPath 中执行此操作。

override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as myCollectionViewCell

    //something like this
    for view in cell.subviews()
        if view == <UIButton>
            view.removeFromSuperview()
        
    
    return cell

我的代码中可能有一些语法错误,我没有测试它,但你知道该怎么做。

【讨论】:

以上是关于快速滚动后在 UICollectionView 中保留按钮内容的主要内容,如果未能解决你的问题,请参考以下文章

当异步添加新项目时,UICollectionView 快速滚动在单元格中显示错误的图像

UICollectionView 快速滚动错误行为

swift iOS - 快速滚动后 UICollectionView 图像混淆

UICollectionView:如何检测滚动何时停止

旋转后在 UICollectionView 中保留第一个可见项目

UICollectionView 在 reloadData 后在屏幕外崩溃时崩溃