Xcode - Getting a cell to display new text after a touch event which makes it expand - objective-c

I'm trying to have a dynamic table which expands on click to reveal some other content. I've got to the point where the table is populated with information from an NSMutableArray. I can also press each cell and it expands to double the size. Now, the next step, which is proving to be somewhat troublesome is to get it to display new/alternative text when they click on the cell. First of all, here's my setup method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
NSString *cellValue = [cellContent objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
return cell;
}
and after this, I have the method where the cell expands on press:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// If our cell is selected, return double height
if([self cellIsSelected:indexPath]) {
return kCellHeight * 2.0;
[cellContent replaceObjectAtIndex:[self cellIsSelected:indexPath] withObject:#"NEW STUFF HERE"];
}
I must be going about this in the wrong way as nothing changes when I touch the cell. How do I get it to display new/alternative text on touch? Any help would be super, I think it's likely to be something quite easy, but I can't see it at the moment.
Thanks!

Your second method is only triggered when the cell is built or rebuilt. You need to explicitly ask it to refresh itself in the following method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
And then within that method, you can call
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
and now your redraw methods will be triggered, so you can handle whatever you want there.

Related

Implementing a search bar?

I have a project with a tableView created on the storyboard. It's pretty simple and I was following a tutorial to do it, my view controller looks like this
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
cell.textLabel.text = restaurantDisplayNames[indexPath.row];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}else{
cell.accessoryType = UITableViewCellAccessoryNone;
}
[tableView deselectRowAtIndexPath:indexPath animated:YES
];
}
So when you tap on a cell it puts a check mark next to it. Now I want people to be able to search for things. Problem is, Apple changed the search bar for iOS 8 and supposedly made it simpler but I can't find any tutorials on the UISearchController which replaced the depricated method.
So I dragged and dropped a Search Bar and Search Display Controller into my view controller and added the UISearchControllerDelegate, UISearchResultsUpdating> protocol declarations, but I get a crash:
'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
Whenever I tap on the search bar.
I also have the method
-(void)updateSearchResultsForSearchController:(UISearchController *)searchController{
}
But it is empty because I don't know what to put in there. Supposedly it is very easy and only requires a few lines of code to get it up and running, but the one tutorial I found here: http://www.stuartbreckenridge.com/blog/examining-the-new-uisearchcontroller-api now only is in swift but doesn't explain what goes in that method.
I figured it out. Man, some of these things are so ridiculously simple yet you have to dig deep to find answers. You'd think Apple could put some tips in XCode about these things, little warnings or something, but here's how I fixed it:
Apparently you need to add
if (!cell){
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
In the cellForRowAtIndexPath: method so it looks like this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (!cell){
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
cell.textLabel.text = restaurantDisplayNames[indexPath.row];
return cell;
}
So it generates the cell if it doesn't exist. Not sure why, but oh well ...

Search Bar in UITableView doesn't display text in Cell label

Here's where the magic isn't happening:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"songCell";
songViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
long row = indexPath.row;
if (cell == nil) {
cell = [[songViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.songLabel.text = _searchResults[row];
} else {
cell.songLabel.text = _songListArray[row];
}
return cell;
}
I know the _searchResults array is populated with the correct search results and I've edited the numberOfRowsPerSection appropriately. The filter is working correctly, but it won't display the _searchResults[row] text while typing into the search bar. If I don't use the bar, the cells are populated correctly with _songListArray[row].
Something is going wrong in:
if (cell == nil) {
cell = [[songViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
If I don't include the if expression, I get an error. How should I initialize the prototype cell while the search bar is in use? All I get is empty labels, but I know the search is working because if there are no filtered results in the array the table says "No Results" in the middle. Why isn't my songLabel.text updating?? It won't even display text when I set the label to #"HELLO??" instead of the array[row].
You need to have the searchResultsTableView dequeue a cell, not just your main table view. The cellForRowAtIndexPath method should look something like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == self.tableView) {
RDTriangleCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = self.theData[indexPath.row];
return cell;
}else{
UITableViewCell *cell = [self.searchDisplayController.searchResultsTableView dequeueReusableCellWithIdentifier:#"SearchCell" forIndexPath:indexPath];
//RDCell *cell = [self.searchDisplayController.searchResultsTableView dequeueReusableCellWithIdentifier:#"SearchCell" forIndexPath:indexPath];
cell.textLabel.text = self.filteredData[indexPath.row];
return cell;
}
}
In viewDidLoad, you should register the class if you use the code I show above for a standard UITableViewCell.
[self.searchDisplayController.searchResultsTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"SearchCell"];
If you use a custom cell for the search results table, then you should use something like the line I have commented out, and register the nib for that custom cell.

UITableView's indexPathForCell: returns always 0 as indexPath.row

I have a UITableView with custom cells in it. This custom cell looks like a normal cell with Style "Detail Left". But my custom cell has a detail label and a text field, to allow the user to edit the text. I have a Save button where I want to save all data the user entered. I made up the custom cell using this tutorial: http://agilewarrior.wordpress.com/2012/05/19/how-to-add-a-custom-uitableviewcell-to-a-xib-file-objective-c/#comment-4883
To get the user data I set the text field's delegate to the table view controller (self) and implemented the textFieldDidEndEditing: method. In this method I ask for the text field's parent view (= cell) and ask for the indexPath of this cell. The problem is, I always get 0 for indexPath.row, no matter what cell I edit. What am I doing wrong?
Here is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:[CustomCell reuseIdentifier] forIndexPath:indexPath];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell = self.customCell;
self.customCell = nil;
}
cell.label.text = #"Some label text";
cell.editField.delegate = self;
cell.accessoryType = UITableViewCellAccessoryNone;
return cell;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
CustomCell *cell = (CustomCell *) textField.superview;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
NSLog(#"the section is %d and row is %d", indexPath.section, indexPath.row);
...
}
EDIT: I just found out, that the returned indexPath is nil. So if it is nil I get the standard values 0, thats okay. But now: Why do I get nil for indexPath?
I just found the solution myself. I found the code for the superview in stackoverflow, so I just copied it. But that does not work. You need to do two superviews like this:
CustomCell *cell = (CustomCell *) textField.superview.superview;
Now it works fine!
Could you just add an index property to your CustomCell and populate it with indexPath.row inside (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

Why is my UITableView not being updated?

Why does my UITableView not update? Here is how I am attempting to update it.
- (void)viewWillAppear:(BOOL)animated
{
NSArray* arrValues = [self.defaults objectForKey:#"values"];
[self.tableScores insertRowsAtIndexPaths:arrValues withRowAnimation:UITableViewRowAnimationNone];
}
arrValues is now an array of NSNumbers. I am sure that it is not empty.
Call [tableScores reloadData]; in - (void)viewWillAppear:(BOOL)animated
Update 1
Also, you need to define arrValues in your header. Each time the viewWillAppear, you are creating a new instance, but you won't be able to use it throughout the rest of your controller. This is the main reason you aren't seeing anything besides at your breakpoint.
Update 2
According to your comment below, you have not implemented cellForRowAtIndexPath: which is how the cell is created. Below is an example, but you may want to search around the net for example projects because this UITableView's 101. There is still a lot more you need to learn when it comes to arrays and tableViews.
Example cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"FriendCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [arrValues objectAtIndex:indexPath.row];
return cell;
}

TableView: didSelectRowAtIndexPath, How to catch a row name

I fill my tableView with random data. So i don't know how many row i have and how to redirect it to screen i want to. I filled:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyClass *currentScreenElement = [self.tableRows objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:currentScreenElement.objectName];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:currentScreenElement.objectName];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.textLabel.text = currentScreenElement.objectName;
return cell;
}
And this works fine. I have a tableView with filled rows. Now i want to redirect to new screen and I doing it with:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NewScreenClass *myScreen = [[NewScreenClass alloc] init];
self.detailViewController = [[CreateView alloc] initWithScreenDef:[myScreen returnScreenFromName:#"second"]];
[self.navigationController pushViewController:self.detailViewController animated:YES];
}
Of course i know that what I actualy do here is create the same screen for every row. But how can i redirect to screen i want to?
My currentScreenElement object contains properties: objectName (display name in tableView) and objectTarget (screen definition). Both NSString.
And my question is should i save a my currentScreenElement to row patch somehow or maybe I should catch a objectName from dislay name?
In didSelectRowAtIndexPath you can get the cell by using
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
Then just get the text from the cell.
cell.textLabel.text
Why can't you use the self.tableRows array again?
MyClass *currentScreenElement = [self.tableRows objectAtIndex:indexPath.row];
NSString *title = [currentScreenElement objectName];
It's the same thing you did to setup that row, just use it again.