Reputation: 3635
For start how I've created expandable cell with UIPicker. Just in case that would be relevant to issue.
It's created in UITableView by this code
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var identifyer = ""
switch(indexPath.row){
//other cells
case 1:
//Kategoria
identifyer = "category"
categoryCell = tableView.dequeueReusableCellWithIdentifier(identifyer) as? CategoryTableViewCell
categoryCell.pickerView.delegate = self
categoryCell.pickerView.dataSource = self
return categoryCell
//other cells
}
Then I have to recognize if it's touched
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if (indexPath.row == 1){
isCategoryCellSelected = true
tableView.reloadRowsAtIndexPaths([categoryIndexPath()], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
That's how I replace text in UILabel
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
categoryCell.categoryNameLabel.text = categories[row]
}
And finaly when tableView refresh cell
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
switch(indexPath.row){
case 1:
if (isCategoryCellSelected){
return CategoryTableViewCell.expandedHeight
} else {
return CategoryTableViewCell.defaultHeight
}
//other heights
}
}
Defalut cell looks
Expanded cell looks
ISSUE
So when I choose item in picker then label above should have change it text and that is happening. However, when this cell shrink to default height then replace effect is gone. I have to scroll down and up to see that only then I can see changed text in label.
I assume that UITableView cache this cell and when cell is reloading then it takes this cached version. I'm only guessing. Is it how I think? How I can change this unwanted action?
As @the_critic pointout my approche to save cells in vars was completly wrong. In same time recreating categoryCell every time I pick row wasn't the correct way to do it. I end up with his way of creating cell but with mine way of setting value to cell.
So it looks like this what's is chagned:
creating cell
categoryIdentifier is private let String
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell
switch(indexPath.row){
// other cells
case 1:
//Kategoria
print("recreate, selected category \(selectedCategory)")
let categoryCell = tableView.dequeueReusableCellWithIdentifier(categoryIdentifier) as! CategoryTableViewCell
categoryCell.pickerView.delegate = self
categoryCell.pickerView.dataSource = self
updateSelectedCategoryIfNeeded(categoryCell)
cell = categoryCell
// other cells
return cell;
}
private func updateSelectedCategoryIfNeeded(cell:CategoryTableViewCell) {
if let selectedCategory = self.selectedCategory{
// A category has been selected!
cell.categoryNameLabel.text = selectedCategory
updatePicekerRowPosition(cell)
}else{
// no category selected!
cell.categoryNameLabel.text = "Wybierz kategorie..."
}
}
private func updatePicekerRowPosition(cell:CategoryTableViewCell) {
if let index = categories.indexOf(selectedCategory!){
cell.pickerView.selectRow(Int(index.value), inComponent: 0, animated: false)
}
}
recognizing row selecting
categoryIndexPath is private let NSIndexPath
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
selectedCategory = categories[row]
if let categoryCell = tableView.cellForRowAtIndexPath(categoryIndexPath) as? CategoryTableViewCell {
categoryCell.categoryNameLabel.text = selectedCategory
}
}
Upvotes: 0
Views: 1696
Reputation: 12820
From what I can see in your code, there are quite a few things you misunderstand about table views.
I would try to say that more politely, but I can't. Your way of referencing a categoryCell in your code is completely wrong! UITableviewCell
s are not static references if you dequeue them!
FIRST STEP: Remove the categoryCell
variable!!!
The way the table view works is the following:
The cellForRowAtIndexPath
method takes a cell from the storyboard or your nib and reuses that cell over and over again! So, in the beginning, you may get away with doing it your way (creating a reference to categoryCell
), but the situation changes as soon as you have more cells than fit on the screen, because the variable will reference a different cell!
Reading recommendation: Creating and Configuring a Table View
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell : UITableViewCell?
switch(indexPath.row){
//other cells
case 1:
//Kategoria
let identifier = "category"
// tableview checks if there is a cached cell
// for the identifier (reuse),
// if there is, it will take that one!
cell = tableView.dequeueReusableCellWithIdentifier(identifier) as! CategoryTableViewCell
cell.pickerView.delegate = self
cell.pickerView.dataSource = self
if let selectedCategory = self.selectedCategory{
// A category has been selected!
cell.categoryNameLabel.text = selectedCategory
}else{
// no category selected!
cell.categoryNameLabel.text = "Wybierz kategorie..."
}
return cell
//other cells
}
As you can see above, I introduced a new variable called selectedCategory
, which will reflect which category is currently selected...
Set it up like this in your controller:
var selectedCategory : String?
What happens when you reload a section or row or the whole table, is that all the UITableViewDataSource
methods for the given rows are called again! In a way the table view always tries to reflect some state of your model.
You should always reflect changes in your model by reloading the row/section or the whole table (depending on what changed).
So when you pick your category, you change the model and reload your row!
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
// update the model!
selectedCategory = categories[row]
// the table view now needs to know that the model changed!
// this will trigger the dataSource method cellForRowAtIndexPath
// and because it selectedCategory is now set, it will update
// your string accordingly!
tableView.reloadRowsAtIndexPaths([/*<IndexPath of your categoryLabelCell>*/], withRowAnimation: UITableViewRowAnimation.Automatic)
}
Phew! I hope that helps...
Upvotes: 1