使用UITableViewController cellForRowAtIndexPath获取重复的单元格

时间:2016-04-19 03:09:04

标签: ios swift uitableview

我正在尝试使用UITableViewController创建表视图。

'cellForRowAtIndexPath'似乎没有正常工作 - 我已经从Parse预装了照片和评论并将它们放在一个数组中,并希望图片填满屏幕宽度,所以我正在做一些手册计算他们调整大小。

我正在做一些不寻常的事情让Table View看起来正确,但现在数据是重复的。

我知道这里有一些我没有得到的东西,但我不确定它是什么......也许我需要做一些别的事来绑定数据,或者用“prepareForReuse”方法做点什么?

我已经包含了UITableViewController子类和我写的UITableCell子类的代码。

import UIKit

class YouTableViewCell: UITableViewCell {

var recipeId:String = ""
var recipeName:String = ""
var imageHeight:CGFloat = 0
var labelHeight:CGFloat = 0

// DO I NEED THIS?
override func prepareForReuse() {
    self.textLabel!.text = recipeId //Put your label name
    self.imageView!.image = nil

}

override func setSelected(selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
 }

 }

 class YouTableViewController: BaseTableViewController { // UITableViewController {

var labelCreated = [Bool]()
var imageCreated = [Bool]()

var cellArray = [Int:YouTableViewCell]()


override func viewDidLoad() {
    super.viewDidLoad()

    self.tableView.delegate = self
    self.tableView.dataSource = self

    self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())

    if !isYouDataLoaded {
        _ = DataController.getYouPageData()
    }


    // initialize height arrays
    for _ in 0..<youFeed.count {
        labelCreated.append(false)
        imageCreated.append(false)
    }


    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = false

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem()
    self.navigationController?.setToolbarHidden(false, animated: false)
}

 // ... skipping down


override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // return feedArray.count
    return youFeed.count
}



override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    print("cellForRowAtIndexPath : \(indexPath.row)")

    // Get reference to cell
    cellArray[indexPath.row] = (tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! YouTableViewCell)
    let thisCell:YouTableViewCell = cellArray[indexPath.row]!


    // TEMP -- Border
    thisCell.layer.borderWidth = 2.0
    thisCell.layer.borderColor = UIColor.blackColor().CGColor

    let meal = youFeed[indexPath.row].recipe

    // If the image exists
    if let foodImage:UIImage = meal.imageView.image! as UIImage {
        var nameLabel:UILabel = UILabel()
        var fitImageView:UIImageView?
        if imageCreated[indexPath.row] == false {
            print("For IMAGE #\(indexPath.row)")
            fitImageView = LayoutHelper.fitImageInCell(foodImage, cell: thisCell, name: meal.recipeName)
            thisCell.contentView.addSubview(fitImageView!)

            thisCell.imageHeight = fitImageView!.frame.height
            fitImageView!.frame.origin.y = 0
            print("img height : \(fitImageView!.image!.size.height)")
            imageCreated[indexPath.row] = true
        }
        if labelCreated[indexPath.row] == false {
            // Create Label
            var captionString = ""
            if let mealNameText:String = meal.recipeName as String {
                captionString += mealNameText
            }

            if let postText:String = meal.desc as String {
                captionString += "\n" + postText
            } else {
                print("Meal Desc is null")
            }
            if let numForks:Int = meal.forks as Int {
                captionString += "\n" + String(numForks) + " Forks"
            }
            if (fitImageView != nil) {
                nameLabel = LayoutHelper.fitLabelBelowImageView(captionString, imageView: fitImageView!, cell: thisCell, yOffset: 0)
                thisCell.addSubview(nameLabel)
                thisCell.labelHeight = nameLabel.frame.height
            }
        }
    } 
    return thisCell
}

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    let thisCell = cellArray[indexPath.row]

    var thisHt:CGFloat = 0
    if thisCell != nil {
        thisHt = thisCell!.labelHeight + thisCell!.imageHeight
    }
    return thisHt
}
}

1 个答案:

答案 0 :(得分:2)

当您重新使用单元格时(这是一件好事!)每次调用cellForRowAtIndexPath时都必须重新初始化整个单元格。这是因为当您拨打此电话时可能会:

tableView.dequeueReusableCellWithIdentifier

它可能会返回您已初始化的单元格。例如,让我们说我在屏幕上可以看到4行:

Row 1 - Cell A [Image 1]
Row 2 - Cell B [Image 2]
Row 3 - Cell C [Image 3]
Row 4 - Cell D [Image 4]

现在,让我们说我向下滚动,第1行不再出现在屏幕上,但第5行现在已经出现了。第5行收到的单元格可能与第1行的单元格完全相同。因此,在调用tableView.dequeueReusableCellWithIdentifier第5行之后,第5行看起来像这样:

Row 2 - Cell B [Image 2]
Row 3 - Cell C [Image 3]
Row 4 - Cell D [Image 4]
Row 5 - Cell A [Image 1] <--

您需要更新单元格A以指向图像5.这可能在您的代码中正常工作,您可以这样做:

Row 2 - Cell B [Image 2]
Row 3 - Cell C [Image 3]
Row 4 - Cell D [Image 4]
Row 5 - Cell A [Image 5] <--

现在,让我们说你向后滚动,第1行再次被分配给小组A:

Row 1 - Cell A [Image 5] <--
Row 2 - Cell B [Image 2]
Row 3 - Cell C [Image 3]
Row 4 - Cell D [Image 4]

由于您要存储的数组可以跟踪哪些行已初始化(imageCreatedlabelCreated),因此单元格不会更新为指向图像1:

// THIS WILL BE TRUE, SO IT WILL NOT EXECUTE
if imageCreated[indexPath.row] == false

这意味着摆脱imageCreatedlabelCreated数组并执行代码以在每次调用cellForRowAtIndexPath时初始化您的单元格。

另外,我建议删除cellArray而不存储对单元格的引用(出于与上面提到的相同的原因)。您可以缓存单元格高度,这应该没问题,因为它们与可重用单元格无关。你可以这样做:

var cellHeightArray = [Int:CGFloat]()

由于您在cellForRowAtIndexPath进行计算,因此在底部设置高度:

cellHeightArray[indexPath.row] = thisCell!.labelHeight + thisCell!.imageHeight;

然后从heightForRowAtIndexPath中的数组中设置它:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    let thisCellHeight = cellHeightArray[indexPath.row]

    var thisHt:CGFloat = 0
    if thisCellHeight != nil {
        thisHt = thisCellHeight
    }
    return thisHt
}

默认情况下,我相信在heightForRowAtIndexPath之前调用cellForRowAtIndexPath。在这种情况下,在重新加载tableview之前,某些单元格的高度为0。请查看此帖子以获取更多信息:

Why does heightForRowAtIndexPath: come before cellForRowAtIndexPath:?