I want to customize a cell in my UITableView subclass. But I cannot figure out is there any way to do it without defining itself dataSource, because it's obviously override external dataSource.
So basically I want to be UITableView dataSource without rewriting this property.
I have already come up with some dirty workaround. I'm reloading the -setDataSource: method to keep UITableView dataSource itself and save incoming data source into an internal variable for passing the requests to it.
You only need to override cellForRowAtIndexPath: and make your cell modifications there. The datasource will populate the cell as usual.
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Calling super will let the datasource methods be called
UITableViewCell * cell = [super cellForRowAtIndexPath:indexPath];
//Do whatever to the cell here
return cell;
}
You can customize your cell in one of two ways: code or interface builder. The tableview datasource is the DATA you want to show, it has nothing to do with the presentation of that data.
What do you want to customize about your tableview? Changing fonts, font colors and background colors are easy to do. If you want to add additional ui elements, like images, more labels, then the quickest way is to use Interface Builder.
Related
At my experiment I need to have reference to first UITableViewCell in tableView. By some action I need to set image and some other cell properties and to keep this state of this only cell even if the tableView will be scrolled. All of this properties can be potentially nulled via scrolling (and they actually are) because of reusing. For set this properties every time cell appears on screen, inside of `-cellForRowAtIndexpath' I tried to catch first cell using:
UITableViewCell *firstCell = (UITableViewCell *)[atableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
but looks like this way I can only catch every next first cell on next scrollable "screen".
So, how can I get ref to first UITableView cell?
If I understand you correctly, you are trying to do something special if the cell at (0, 0) is about to be displayed, right? If that's the case, you can easily implement UITableViewDelegate's tableView:willDisplayCell:forRowAtIndexPath: method as follows:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath) {
// Do something special
}
}
There is also a corresponding tableView:didEndDisplayingCell:forRowAtIndexPath: method if you need to undo things.
Hope it helps!
There is no "first" table view cell. The entire table view typically uses a single cell to improve performance.
You can change that, by implementing your own cell reuse system (search for reuse in the documentation). But generally the cell is the wrong place to store any data related to a specific index in the table view.
Trying to recognize a selection TableViewCell. They're static cells, not needing any scrolling. Do I need to implement the UITableView? Is there a way just to add actions to the TableViewCells without implementing the TableView and associate methods?
It's not clear what you want or why you would want to do it without using a table view. But, if you implement a UITableViewController that controls a static table view, you don't have to implement any of the usual data source methods. You could just implement the delegate method, tableViewDidSelectRowAtIndexPath:, and use that to provide the actions when you select a cell.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0)
//do some action;
if (indexPath.row == 1)
//do some other action;
//etc.
}
UITableViewCell is a subclass of UIView, so you can add it to any view as a subview. But UITableViewCell is designed to use in UITableView, you cannot make it work perfectly if you not use UITableView. Why not using a UITableView to contain the cells? You can set tableview.scrollEnabled = NO; to make it static.
I have a UITableView and each UITableViewCell contains an editable UITextView.
My data source is a NSMutableArray containing NSMutableDictionary that holds the text value and some styling keys for the text.
How can I (efficiently) make it so that any changes a user makes to the UITextView are updated in the corresponding datasource NSMutableDictionary?
A rather simple way is to utilize the index path of the table, it is NOT the cleanest so it depends on the complexity of your datasource, and if you have multiple tables etc.
What you can do is when the user ends editing the textView or selects another row in tableView, you read the indexPath of the selected row (That requires that the row keeps actually being in the selected state while editing the textView which it should by default). From there you call your update method.
To catch the end of editing you implement
-(void)textViewDidEndEditing:(UITextView *)textView
{
NSIndexPath *selectedpath = [myTable indexPathForSelectedRow];
[self myUpdateMethodForIndexPath:selectedpath];
}
To catch deselect of the table row and the above doesnt get called, you implement
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self myUpdateMethodForIndexPath:indexPath];
}
Your update method must then read the value of the textView at the corresponding cell at the indexPath and handle this in the datasource. To care for sections of course you need to correctly handle the indexPath, in the example just the row is used (1 section).
-(void)myUpdateMethodForIndexPath:(NSIndexPath *)editPath
{
UITableViewCell *editCell = [myTable cellForRowAtIndexPath:editPath];
NSString *newText = editCell.theTextView.text;
....
NSMutableDictionary *dict = [myDictArray objectAtIndex:editPath.row];
....
}
First of all, you must assign a tag to each UITextView, to know exactly which UITextView are you refering.
Then you must implement UITextViewDelegate in your view controller which holds the tableview. Then, make this view controller the delegate of each UITextView. Read here how to implement it: UITextViewDelegate reference.
Look for the protocol method that better fits your needs (probably – textView:shouldChangeTextInRange:replacementText:, wich is called each time the text changes in any range.
In the delegate method, you can read the text with UITextView.text property, and assign this value to your data model (the dictionary).
Another possible approach is to use KVO pattern, but it requires more coding and a better understanding both, the pattern and the implementation. Hope it helps!
Make your view controller the delegate of each text view. Listen for appropriate events to get the updated text. Then have the view controller update the data model with the updated text.
If you have custom cells then have the cell be the text view delegate. Then the cell should notify its delegate (the view controller) about the updated text. Of course this requires that your custom cell class define its own delegate protocol and the view controller should make itself the delegate of each cell.
That's as specific as an answer can be for such a vague question.
I have a UITableViewController with prototype cells containing UITextFields. To configure these custome cells, I've created a UITableViewCell subclass. I've conected the textField to the cell subclass via an outlet (nonatomic, weak).
On this subclass I've created a protocol for which the UITableViewController is its delegate so that everytime something changes in these textFields, the TableViewController knows about it. Basically I wanted this to save the values on the NSUserDefaults
Besides, in order to dynamically obtain values from these textFields, I can do something like this:
((TextFieldCell*)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]]).textField.text
It works ok most of the times. However when the textField is outside of the view because it has scrolled, the vaulue I get from textField.text is (null). As soon as it gets in the view again, everything goes back to normal.
I tried to change the outlet from weak to strong but to no avail.
I guess I could define some private NSStrings on the class, and fill them out when the delegate protocol gets called. The thing is that I wanted to get my code as generic as possible, keeping the need for private variables as low as possible, mostly to simplify the cell generation code.
Is there any other way to get the values of the textFields when they are outside of the view?
Thanks in advance!
But you know that UITableView only keeps Cells for the visible rect?
When a cell leaves the screen, and a new cell is needed for another cell moving into the visible area, the old cell is reused for the new content.
So there is not one cell for each row of your table view.
And if your table contains a lot data, there are far more rows than cells.
As Thyraz said, the UITableView only keeps cells for the visible rect -- and a reasonable buffer to allow for scrolling. Thats why 'reuse identifiers' are so very important, they indicate which cells can be used for which tables (critical when you have more than one table to worry about). Unfortunately, that doesn't answer your question by itself.
The responsibility for storing the contents of those textViews isn't on the UITableView's shoulders. It's your job to provide that data through the data source delegate protocols, and therefore you should be querying the data source for that information.
Edit: Which means that yes, you should be storing this data somewhere else, usually in the form of properties on the view controller class that contains the table view. I'd recommend the use of NSArray for the purpose, but you can also do it through dicts or even, at the last resort (and this is more a in theory you can do this, but it's an incredibly bad idea kind of thing), a series of properties. Personally, I almost always use NSArrays because they're structured in a manner appropriate to the problem, but you could theoretically do it other ways. (I've used a dict based structure exactly once, and that was a situation where my data was nested inside itself in a recursive structure)
UITableViewController doesn't keep cells around once off the screen. You can use the following pattern to get a previously used one as a memory management optimization, but you MUST assume that cells need to have the values reset on them every time they come onto the screen (even if dequeued) because there is no guarantee what the values will be.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"Cell1";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if( cell == nil ) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier1] autorelease];
cell2.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell2.editingAccessoryType = UITableViewCellAccessoryNone;
}
switch( indexPath.section ) {
case first_Section:
if( row == 0 ) {
cell1.textLabel.text = #"Some Text";
cell1.accessoryView = [self myCustomViewControl];
cell = cell1;
}
... etc
}
}
I am looking to have custom UITableViewCells for my UISearchDisplayController. The searchResultsTableView is a readonly property. I have the delegate and datasource for the searchviewcontroller returning the custom cells, however, it seems to still be using the searchResultsTableView cells. What's the best way to have the search results using my own UITableViewCells?
When a search begins, a whole new UITableView is created. This new table view will use default settings and won't match your table view. In your UISearchDisplayDelegate, override searchDisplayControllerWillBeginSearch: in order to re-theme the new UITableView, like this:
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
// Re-style the search controller's table view
UITableView *tableView = controller.searchResultsTableView;
tableView.backgroundColor = [UIColor blueColor];
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
}
I'm not sure I fully understand the question, but it sounds like you want two different UITableViewCell types (subclasses?) to be returned when you're typing a search, or when you're not searching. Is that right?
Like John said, and depending on how you hooked up the UISearchDisplayController, both the search results table view and your default table view will fire cellForRowAtIndexPath and willDisplayCellForRowAtIndexPath. In those methods you can check which tableView is asking for the cell and customize it as necessary. I customize the background, text and color of my cells and this approach works well for me. I can post code if you'd like.