I have an uitableview with a custom cell which gets data from the array.
Custom cell has an uilabel and an uibutton (which is not visible until the uilabel text or the array object which loads for the text - is nil).
On launch everything is fine. When i press the uibutton the array is being appended, the new cells are being inserted below the cell.
But when i scroll - all of a sudden the uibutton appears on other cells where this conditional uilabel text isEmpty is not implied.
Here is how the whole process looks like
Here is my code for cellForRowAtIndexPath
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:TblCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! TblCell
cell.lblCarName.text = someTagsArray[indexPath.row]
if let text = cell.lblCarName.text where text.isEmpty {
cell.act1.hidden = false
} else {
println("Failed")
}
cell.act1.setTitle(answersdict[answersdict.endIndex - 2], forState:UIControlState.Normal)
cell.act2.setTitle(answersdict.last, forState:UIControlState.Normal)
return cell
}
So my general question is how do i stop the reuse of those custom cells?
As far as i'm aware there is no direct way of doing this on reusablecellswithidentifier in swift, but maybe there are some workarounds on that issue?
When a cell is reused, it still has the old values from its previous use.
You have to prepare it for reuse by resetting that flag which showed your hidden control.
You can do this either in tableView:cellForRowAtIndexPath: or the cell's prepareForReuse method.
Update:
Here's an example you can add for TblCell:
override func prepareForReuse()
{
super.prepareForReuse()
// Reset the cell for new row's data
self.act1.hidden = true
}
Related
I am creating a form in UITableViewCell, this form has lable and text field, in prototype cell. See its image here
TableView Story board Image.
I am using identifier to dynamically create the form, my code is
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("protocell", forIndexPath: indexPath) as! UITableViewCell
var lable = cell.viewWithTag(1) as! UILabel
lable.text = details[indexPath.row]
lable.textColor = UIColor.brownColor().colorWithAlphaComponent(0.7)
var textfield = cell.viewWithTag(2) as! UITextField
textfield.placeholder = "Enter \(details[indexPath.row])"
self.arrayTextField.append(textfield)
if details[indexPath.row] == "Name" {
textfield.placeholder = "Enter First \(details[indexPath.row]) Middle \(details[indexPath.row]) Last \(details[indexPath.row]) "
}
textfield.backgroundColor = UIColor.redColor().colorWithAlphaComponent(0.2)
return cell
}
Now the problem is I am having 18 fields and when I enter values in the field and scroll the the view to fill the remaining fields, the values changes in the fields changes.
Please help.
Create UITableViewCell subclass and override prepeareForReuse function - to turn cell to default mode.
Swift:
override func prepareForReuse() {
super.prepareForReuse()
//set cell to initial state here, reset or set values, etc.
}
As per your comment - of how to subclass UITableViewCell:
import UIKit
class MyCustomCell: UITableViewCell {
// things that you can do here:
// initialise your properties here. (label, textfield. etc)
// layout subviews.
// override superclass APIs.
}
Do not store the textfields in an array instead datasource "details" array should do it.
Once you have entered any thing in the textfield update you "details" array for that indexPath.
Subclass UITableViewCell and make a CustomTableViewCell and have IBOutlets for you textfields labels and what not to make your life easier
Have a method on your CustomTablewViewCell like updateWithDetails(details) so that the code is well encapsulated
Here is the really weird behavior. When the table view is first loaded, it looks like this:
Now, when I scroll down and then scroll back up, the buttons appear on cells that didn't have buttons on them before! Like so:
I know this has to do with "This is the intended behaviour of a UITableView. The whole point of a UITableView is to queue up cells that are needed and release cells that aren't needed to manage memory" as described in this post: UITableView in Swift: Offscreen cells are not pre-loaded.
Here is my code:
var messages = [String]()
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CathyTaskLogTableViewCell
if messages[indexPath.row] != "" {
cell.messageButton.hidden = false
}
return cell
}
Anybody have a solution to this problem?
The reason for getting this result is because of UITableViewCell is being reuse.
if messages[indexPath.row] != "" {
cell.messageButton.hidden = false
}
else
{
cell.messageButton.hidden = true
}
There are two possible solutions to your problem:
Always set the hidden property:
cell.messageButton.hidden = messages[indexPath.row] != ""
Reset the state of your cell when it is reused, this provides deterministic behaviour in the table view controller, without burdening the controller class with tasks that a cell should do. This can be done by overwriting prepareForReuse in CathyTaskLogTableViewCell.
func prepareForReuse() {
super.prepareForReuse()
self.messageButton.hidden = true // or false, depending on what's the initial state
// other stuff that needs reset
}
With the current code, messageButton gets hidden only if the cell doesn't find something in messages. So for cells that had this button visible, were reused, and now correspond to a cell that doesn't have a correspondent in messages, the button will remain visible.
Currently I have a few of custom cell's prototypes created in Storyboard with text fields embedded in them. To access these text fields, I use nameTextField = cell.viewWithTag:(1) in cellForRowAtIndexPath:. But viewDidLoad: and viewWillAppear: methods get called before cellForRowAtIndexPath, so at that time nameTextField is nil. To populate text fields when table view shows on screen, I use viewDidAppear:, but it results in a noticeable delay. Also, when I scroll table view up and down, cellForRowAtIndexPath: gets called again and again, resetting already entered data in text fields.
Are there more efficient ways to populate text fields embedded in custom cells' prototypes with data just before the view shows up, and to prevent resetting of entered data in each cellForRowAtIndexPath: call?
I guess you're creating profile screen (or something with many textField to get input data from user). Am I right?
If I'm right, you can use a static tableView (when you have a few textFields)
Hope this can help.
I'm not sure I understand completely what you're trying to do, but cells are normally configured in the cellForRowAtIndexPath: method, not in viewDidLoad. You can also try connecting the textfield to an outlet on your custom cell class. Then you can do:
// in view controller
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
as! CustomCell
let object = myDataSource[indexPath.row]
cell.textField.text = object.description
cell.shouldBecomeFirstResponder = indexPath.row == 0
return cell
}
// then in the cell
class CustomCell: UITableViewCell {
#IBOutlet weak var textField: UITextField!
var shouldBecomeFirstResponder: Bool = false
override func awakeFromNib() {
if shouldBecomeFirstResponder {
textField.becomeFirstResponder()
}
}
}
Then when users input text into the textfield, it would make sense to update your data source.
In viewDidLoad try to run something like self.tableView.reloadData before you do this line "nameTextField = cell.viewWithTag:(1)".
I'm trying to create an autocompleter using iOS 8, Swift and Xcode 6.3
I have a problem that I'm trying to solve, but I gave up... I hope someone can help here. The problem is that (custom) UITableViewCell's are not displaying when the initial dataSource is empty. When adding data to datasource and reloading the tableView, the cells SHOULD display, but they don't... At least, the first time they don't... A second time, they DO... When I initialize the table with non-empty data, the problem doesn't occur. I guess something goes wrong with dequeueReusableCellWithIdentifier. In beginning, no reusable cells are found, or something. But I don't know why...
Relevant code, in ViewController.swift:
// filteredWords is a [String] with zero or more items
#IBAction func editingChanged(sender: UITextField) {
autocompleteTableView.hidden = sender.text.isEmpty
filteredWords = dataManager.getFilteredWords(sender.text)
refreshUI()
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! AutocompleteTableViewCell
cell.title.text = filteredWords[indexPath.row]
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredWords.count
}
func refreshUI() {
self.autocompleteTableView.reloadData()
}
I created a sample project on github:
https://github.com/dirkpostma/swift-autocomplete
And a movie on YoutTube to show what goes wrong:
https://www.youtube.com/watch?v=ByMsy4AaHYI
Can anyone look at it and spot the bug...?
Thanks in advance!
You've accidentally hidden your cell.
Open Main.storyboard
Select Cell
Uncheck Hidden
Side note: As for why it's displaying the second time around with the cell hidden? It appears to be a bug. It should still be hidden (print cell.hidden, notice it's always true despite showing the text on the screen).
I think you need to change your code. Check out below code. It is because if you remember in Objective C you needed to check if the Cell was nil and then initialise it. The reuse identifier is usually reusing an already created cell, but on the first launch this does not work because there is no Cell to use. Your current code assumes always that the cell is created (re-used) because you are using ! in the declaration, so if you use the optional (?) it can be null and you then can create the cell
var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? AutocompleteTableViewCell
if cell == nil
{
//You should replace this with your initialisation of custom cell
cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "CELL")
}
cell.title.text = filteredWords[indexPath.row]
return cell
This lengthy title is roughly my problem. I started simple learning example using UICollectionView in Swift project.
I added CollectionView to ViewController created by template, assigned delegate and data source. Custom cell is created in storyboard. Reuse identifier is set.
Everything is fine so far. I have placed one UILabel in custom cell, and gave tag value 100.
Here's code of my ViewController: https://gist.github.com/tomekc/becfdf6601ba64d5fd5d
And interesting exceprt below:
func collectionView(collectionView: UICollectionView!, cellForItemAtIndexPath indexPath: NSIndexPath!) -> UICollectionViewCell! {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("element", forIndexPath: indexPath) as UICollectionViewCell
cell.backgroundColor = UIColor.yellowColor()
// list subviews
NSLog("--- ROW %d ---", indexPath.row)
printSubviews(cell)
if let labelka = cell.viewWithTag(100) as? UILabel {
labelka.text = String(format: "Row %d", indexPath.row)
NSLog("Found label")
}
return cell
}
func printSubviews(view:UIView) {
if let list = view.subviews as? [UIView] {
for uiv in list {
NSLog("%# tag:%d", uiv, uiv.tag)
printSubviews(uiv)
}
}
}
The problem is that cell.viewWithTag(100) returns nil until cell is reused. When I scroll the view so any of cells goes out of window and reuse is forced, viewWithTag(100) returns the label and I can set its value.
What's interesting, I put together similar example in Objective-C and there is no such problem. Even when built and run with XCode6 beta4.
I wonder if I missed something or this is wrong behavior?
Update: apparently I took too simplistic approach. When I created custom UICollectionViewCell subclass (as I usually do), result is correct.