I have a tableview that is based on a array of DB results, these results contains a date field. I have a custom cell that contains an image and labels. I'm trying to do:
At cellForRowAtIndexPath I verify if the date of current item (objectAtIndex:indexPath.row) has date field bigger than the last item (objectAtIndex:indexPath.row-1). If this is true: I want to add a cell filling the ImageView with a certain image, but I need to add a new row just for show this image.
How can I do this? I'm already doing this verification, but I need to add a new cell...
Do not use the cellForRowAtIndexPath to decide how many cells you want to have. At the point this method is called you should have already setup the data source to provide table view with all information needed.
Here is what you need to do. Refactor your code in a way so you:
Setup the data source first.
Force reload of the table view either by calling the reloadData method.
hey you can add the object in your data base(for example ns array) and refresh the table view with method
[tableView reloadData];
then the method cell for row at index path will be called again and it will refresh the table view's items.just make sure the method cellforrawantindexpath in your code knows to handle the new data type(make validations).
Your tableView data source should not contain any of that logic where the content of once cell depends on the content of another cell. Instead, you should have a data item for each requested indexPath and that data item should contain ALL logic necessary for the cell to be configured. If an action on that cell has an effect on how another cell should look, you apply a change to the corresponding data-item, and then call reloadRowsAtIndexPaths: for the indexPaths.
In short: configure cells ONLY in tableView:cellForRowAtIndexPath: or tableView:willDisplayCellAtIndexPath, and ONLY do configuring. Other logic should be placed in some data(-controller) object.
As suggested, you should add an item to your data-array. Then call -insertRowAtIndexPath: on the tableView. ReloadData is like a big ugly hammer that you only use when ALL of the data for that tableView changes.
Related
I'd like to get every data that is within all cells in one tableview which is quite a long list.
I'm looking for an approach on how to retrieve everything including those hidden in view, which I know the views are reused. I think some of you might have experienced this problem before, what are your approach on this?
I've tried
let cells = self.tableView.visibleCells
then looping into every cell and saving each data to an array but it is not effective in getting those that aren't part of the view or hidden. Is there a way to get over this?
In cellForRowAtIndexPath, YOU are telling the table what is in each cell. So why would you turn around and ask the table what's in each cell? If the user puts "Hello" in your first cell, then scrolls the table enough to push that first cell out of view, then when the user scrolls back to the top, YOU are the one telling it to put "Hello" back in that first cell. YOU own the data source, not the table.
You need a data source. That can be "empty" at first, maybe an array of empty strings if that's what you want (each index in the array could map to a table row for example). But then, as the user interacts with the text fields in the cells, you need to update that data source with the text they entered.
You should use that data source as your source for the cellForRowAtIndex method. That way you can handle populating the cells when they are requested by the table, and you also know all the data when the user is done.
Why not just update the model each time the user taps a key when editing a textfield? You could create a protocol for that cell subclass and make your view controller the delegate for each cell. As long as cells are guaranteed to stay on the screen while you're typing (you'll get some weird behaviors if not) the cell can send a message to the view controller or whatever you hook it up to telling it what new value to store. Then everything is already stored for you when you need the full list, and you don't have to interact with the tableview.
I have another question open where I'm trying to figure out how to reload the collectionView without auto-scrolling. I was also realizing there are a lot of other situations where I will need to change things in the collection view. Also I have some items that I will want to change the .alpha on and change the text of. Is there a way to do all of this in Swift? For example (to be specific) if I have a collection view with a view in each cell and that view has a textField in it, can I change the alpha and text, (change alpha with animation even) without reloading entire table?
Look at the documentation for UICollectionView. There are several "reload" methods:
reloadData()
reloadSections(_:)
reloadItems(at:)
If you just want to reload a single item, update your data source's data and then call reloadItems(at:) passing in the index path for the item.
Another option, if a cell is currently visible, is to use the cellForItem(at:) method to get a reference to an existing cell. Then you can directly access UI components of the cell as needed. You should also update your data model as needed so if the user scrolls and comes back, the cell will be rendered properly.
Most appropriate where you can update your custom view of a particular UIcollectionViewcell is reloadItemsAtIndexPaths.
You would be handling a particular item than whole collectionview with reloadData.
You can handle it via notifications or some call backs in your code where you can make decision when to update which cell.
Hope it will help you.
I have a UITextView and when I press a 'Save' button I would like that the text will get added to a row in my UITableView. I've set up the table view already. I'd also like to get to the UITextView when selecting one on the table view.
First, you need to add the data to your data source. Depending on how your table is set up that might just entail adding an extra string to an array, if you edit your question with more detail I can be more specific here.
Next you call insertRowsAtIndexPaths:withRowAnimation: on your table view, changing the value of the index path depending on where you've added the new data.
[tableView insertRowsAtIndexPaths:#[NSIndexPath indexPathForRow:0 inSection:0] withRowAnimation:UITableViewRowAnimationAutomatic];
The table view will take care of the rest, it will call cellForRowAtIndexPath: to make the new table cell (using the data you just added to the data source) and will even animate it into position for you.
For the second part of your question, you'll need to implement tableView:didSelectRowAtIndexPath: and in there get the appropriate string from your data source based on the selected row, and set the text view accordingly. Something like
textView.text = myDataSourceArray[indexPath.row];
Very basic, but this example should do the trick.
https://cloud.jakota.de/public.php?service=files&t=922500d0732da5ce3cc71b6fdf517a83
I have a TableView with a prototype cell, in this prototype cell I have a text field.
Well, what I need is to get a information from this text field when it changes. I need to do that to feed a object.
How can I do that ?
Short answer - you don't.
Slightly more in depth answer...
The UITableViewCell is a "view". It is used only to display information to the screen. It is not for storing data in.
In a UITableViewController (i.e. UITableViewDatasource and UITableViewDelegate) you should have an NSArray (or an NSFetchedResultsController) that you use to store information in.
Then using the delegate methods you populate the table with that data.
If the data changes then you reload the table to update the cells.
What should never happen is the following...
Load the table by passing in data to the cell.
The cell then changes its own data and changes what is on the screen.
The controller then reads that data out of the cell.
No, no, no, don't do this.
What should happen is this...
Load the table and configure the cell display to represent the correct part of the data.
When the button is pressed (or text field is changed, etc...) in the cell then call a method back in the controller to update the data accordingly.
Now the data has changed, reload the cell.
It will now show the correct information based on the new data.
You need a custom cell with a public property (IBOutlet) UITextfield. Then you can set your ViewController as the textField's delegate in cellForRowAtIndexPath,
cell.textField.delegate = self;
in this case your ViewController has to implement UITextFieldDelegate protocol.
I have a table view cell that has many rows with a UITextView. In those UITextView the user can enter values.
The problem that I have is that if I want to get the value of a row when the row is hidden I get nil.
NSString *cellValue = ((UITextField *)[[[self.table cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]] contentView] viewWithTag:[self.table cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]].tag]).text;
I was thinking to save the value that the user enters in the UITextField, but if the user clicks a row that performs the calculate the delegate textFieldDidEndEditing is not being called.
I don't know how can I get this values in a secure way.
You should target the data source that is behind the UITableView. The UITableView is just a display mechanism and not the primary resource for getting to data. You can get the index for the cell based on the title, but then I would look tot he data source to get your actual data. Better yet I would just handle all operations against the data source itself if that is possible. When you build the table initially your data source is a list or array of some kind I am sure so you can just use it. You may need to create a variable on the view and retain the list/array there to make sure you have it and you should be all set.
Good Luck!
As mentioned, you would generally use the UITableView data source to access this.
That said, you are probably not seeing the data you expect because the you are using dequeued cells. If the number of cells is small, you could consider caching your own cells in an NSDictionary whose keys are some combination of the section and row, and accessing their view hierarchy via your own cache.
You can access rows that are not currently displayed by directly referring the tableView's dataSource with the wanted IndexPath.
You can achieve this by doing something like this (when using Swift 3):
UITableViewCell cell = self.tableView(self.tableView, cellForRowAt: indexPath)
What is happening most likely is your reusing cells. So when your cell with the textfield goes off screen it gets reused so you cannot access it anymore. What you will need to do is grab the value out the the textfield right after they enter it and store it somewhere. You can use – textField:shouldChangeCharactersInRange:replacementString: so that when ever the user enters a character into the textfield you can save the string.