使用 UITableViewController cellForRowAtIndexPath 获取重复的单元格 [英] Getting duplicate cells with UITableViewController cellForRowAtIndexPath
问题描述
我正在尝试使用 UITableViewController 创建一个表视图.
I am trying to create a Table View using a UITableViewController.
'cellForRowAtIndexPath' 似乎工作不正常——我从 Parse 预先加载了照片和评论并将它们放在一个数组中,并且想要填充屏幕宽度的图片,所以我正在做一些手动操作对它们进行计算以调整大小.
The 'cellForRowAtIndexPath' doesn't seem to be working right-- I have pre-loaded photos and comments from Parse and put them in an array, and want pictures that fill up the screen width, so I am doing some manual calculations on them to resize.
我正在做一些不寻常的事情以使表格视图看起来正确,但现在数据重复了.
I am doing some unusual things to get the Table View to look right, but now the data is duplicated.
我知道这里有一些我没有得到的东西,但我不确定它是什么......也许我需要做一些其他事情来绑定数据,或者使用prepareForReuse"方法做一些事情?
I know there is something here that I'm not getting, but I'm not really sure what it is... maybe I need to do something else to bind the data, or do something with the "prepareForReuse" method?
我已经包含了来自 UITableViewController 子类和我编写的 UITableCell 子类的代码.
I have included code from the UITableViewController subclass and the UITableCell subclass I wrote.
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
}
}
推荐答案
当你重复使用单元格时(这是一件好事!)你必须每次都重新初始化整个单元格 cellForRowAtIndexPath
被调用.这是因为当您拨打此电话时,可能:
When you re-use cells (which is a good thing to do!) you must re-initialize the entire cell every time cellForRowAtIndexPath
is called. This is because it is possible that when you make this call:
tableView.dequeueReusableCellWithIdentifier
它可能会返回一个您已经初始化的单元格.例如,假设我在屏幕上有 4 行可见:
it could be returning a cell that you have already initialized. For example, let's say I have 4 rows visible on the screen:
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 行看起来像这样:
Now, let's say I scroll down and Row 1 is no longer on the screen, but Row 5 has now appeared. It is possible that the cell you receive for Row 5 is the same exact cell that was at Row 1. So, immediately after the call to tableView.dequeueReusableCellWithIdentifier
Row 5 looks like this:
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.这可能在您的代码中工作正常,您会得到:
You need to update Cell A to point to Image 5. That may work fine in your code and you get this:
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:
Now, let's say you scroll back up and Row 1 is assigned Cell A again:
Row 1 - Cell A [Image 5] <--
Row 2 - Cell B [Image 2]
Row 3 - Cell C [Image 3]
Row 4 - Cell D [Image 4]
由于您存储的数组用于跟踪已初始化的行(imageCreated
、labelCreated
),因此单元格不会更新为指向图像 1:
Since you are storing arrays that keep track of which rows have been initialized (imageCreated
, labelCreated
) the cell won't get updated to point to Image 1:
// THIS WILL BE TRUE, SO IT WILL NOT EXECUTE
if imageCreated[indexPath.row] == false
这意味着摆脱您的 imageCreated
和 labelCreated
数组,并在每次调用 cellForRowAtIndexPath
时执行代码来初始化您的单元格.
This means get rid of your imageCreated
and labelCreated
arrays and perform the code to initialize your cells every time cellForRowAtIndexPath
is called.
另外,我建议去掉 cellArray
并且不存储对单元格的引用(出于我上面提到的相同原因).您可以缓存单元高度,这应该没问题,因为它们与可重用单元无关.你可以这样做:
Also, I would recommend getting rid of the cellArray
and not storing references to cells (for the same reasons I mentioned above). You can cache cell heights and that should be fine because those are not tied to re-usable cells. You could do something like this:
var cellHeightArray = [Int:CGFloat]()
由于您在 cellForRowAtIndexPath
中进行计算,因此将高度设置在底部:
Since you are doing calculations in cellForRowAtIndexPath
set the height at the bottom:
cellHeightArray[indexPath.row] = thisCell!.labelHeight + thisCell!.imageHeight;
然后从heightForRowAtIndexPath
中的数组中设置:
Then set it from the array in 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
之前被调用.在这种情况下,您的某些单元格的高度将为 0,直到您重新加载 tableview.查看此帖子了解更多信息:
By default, however I believe heightForRowAtIndexPath
is called before cellForRowAtIndexPath
. In that case some of your cells will have a height of 0 until you reload the tableview. Look at this post for more information:
为什么 heightForRowAtIndexPath: 在 cellForRowAtIndexPath: 之前?
这篇关于使用 UITableViewController cellForRowAtIndexPath 获取重复的单元格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!