[Edited Post]
For practicing, I developing a contact app without any backend. I followed only one NSMutableArray for maintaining contacts which is displayed in a UITableView.
Objective;
Like to search a contact (Ex: Dad), user given a name in a textfield and touch up a button
In the button action, check if Dad contain in the Mutable array which one i followed.
If present, then it definitely present in the tableView as a row. So i want to put selectionStyle for that row.
If search text changes means (Ex: Mom), then revert previous selectionStyle and apply to the row(Mom).
If not present, label notify "Not Present" as text. (Done!).
IBAction:
-(IBAction)actionSearchNameInTable:(id)sender{
if([myContactsArray containsObject:txtForContactName.text]){
myTable.tag=5;
NSInteger tempIndex=[myContactsArray indexOfObject:txtForContactName.text];
NSIndexPath *tempIndexPath=[NSIndexPath indexPathForRow:tempIndex inSection:0];
[self tableView:myTable didSelectRowAtIndexPath:tempIndexPath]; //broke here
NSLog(#"Call Passed!");
}
}
didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if(myTable.tag==5){
NSLog(#"called done!");
//Here i like to select that row and apply selectionStyle or favorite background color for that cell, idea?.
myTable.tag=0;
}
These are all just other part of my application. I sured that, Delegate and Datasource are connected properly.
You are calling didDeselectRowAtIndexPath and not didSelectRowAtIndexPath.
And I think you have not implemented didDeselectRowAtIndexPath in your class so thats the reason of crash.
and for your another question:
-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(cell.tag==100)
{
cell.contentView.backgroundColor=[UIColor grayColor];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell=[tblviw cellForRowAtIndexPath:indexPath];
cell.tag=100;
cell.contentView.backgroundColor=[UIColor grayColor];
}
Change this:
-(IBAction)actionSearchNameInTable:(id)sender{
if([myContactsArray containsObject:txtForContactName.text]){
myTable.tag=5;
NSInteger tempIndex=[myContactsArray indexOfObject:txtForContactName.text];
NSLog(#"TEmp index:%i",tempIndex);
NSIndexPath *tempIndexPath=[NSIndexPath indexPathForRow:tempIndex inSection:0];
NSLog(#"Temp IP:%#",tempIndexPath);
[self tableView:myTable didSelectRowAtIndexPath]; //broke here
NSLog(#"Call Passed!");
}
}
And for custom selection background do this in your cellForRowAtIndexPath.
UIView *customColorView = [[UIView alloc] init];
customColorView.backgroundColor = [UIColor colorWithRed:180/255.0
green:138/255.0
blue:171/255.0
alpha:0.5];
cell.selectedBackgroundView = customColorView;
Hope this helps.. :)
EDIT:
didSelectRowAtIndexPath is a delegate. It only get called when user interaction happens. I face a same problem some days ago. I did it in cellForRowAtIndexPath. For selecting a row do this:
if ([[myContactsArray objectAtIndex:indexPath.row] isEqualToString:txtForContactName.text]) {
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
Please try to see my edited answer...
-(IBAction)actionSearchNameInTable:(id)sender{
if([myContactsArray containsObject:txtForContactName.text]){
myTable.tag=5;
NSInteger tempIndex=[myContactsArray indexOfObject:txtForContactName.text];
NSLog(#"TEmp index:%i",tempIndex);
NSIndexPath *tempIndexPath=[NSIndexPath indexPathForRow:tempIndex inSection:0];
NSLog(#"Temp IP:%#",tempIndexPath);
[self tableView:myTable didSelectRowAtIndexPath:tempIndexPath]; //Change here......
NSLog(#"Call Passed!");
}
}
Action for searching that if given text is present or not:
-(IBAction)actionSearchNameInTable:(id)sender{
[txtForContactName resignFirstResponder];
if([myContactsArray containsObject:txtForContactName.text]){
myTable.tag=5;
[myTable reloadData];
}
}
In cellForRowAtIndexPath:
//Better delegate to apply selection style
//Code after dequeue...
myTableCell.textLabel.text=[myContactsArray objectAtIndex:indexPath.row];
myTableCell.imageView.image=[myContactsPhotosArray objectAtIndex:0];
{
myTableCell.textLabel.text=[myContactsArray objectAtIndex:indexPath.row];
myTableCell.imageView.image=[myContactsPhotosArray objectAtIndex:0];
if(myTable.tag==5){
NSLog(#"Ready to apply selectionStyle");
if ([[myContactsArray objectAtIndex:indexPath.row] isEqualToString:txtForContactName.text]) {
[myTable selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
myTable.tag=0;
}
}
return myTableCell;
}
Related
I have a UITableView as a subview of a View. In the ViewController when the table is being populated I'm highlighting one of the rows and keeping a record of the indexPath for that row. I'm doing this in the cellforRowAtIndexPath method.
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
favouriteCellView *cell = [tableView dequeueReusableCellWithIdentifier:#"reuseID"];
QBCOCustomObject *favouriteObject = [_favouriteResults objectAtIndex:indexPath.row];
if (favouriteObject.userID == self.user.ID) {
UIView *bgColor = [[UIView alloc] init];
bgColor.backgroundColor = [UIColor colorWithRed:173.0f/255.0f green:146.0f/255.0f blue:237.0f/255.0f alpha:.5];
self.highlightedRowIndex = indexPath;
[cell setSelectedBackgroundView:bgColor];
[tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle];
}
return cell;
}
Then in the viewDidAppear Method I want the table to scroll to the highlighted cell.
-(void)viewDidAppear:(BOOL)animated{
[self.tableView scrollToRowAtIndexPath:self.highlightedRowIndex atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
However I've double checked that the method is being hit with a breakpoint, but unfortunately the highlighted row is not being scrolled to the top of the table as I'd expected. AM I misunderstanding the scrollToRowAtIndexPath method? Or have I left something out of the above code.
If the row is not on screen, it will not yet be loaded by the table view. This means your cellForRowAtIndexPath for that cell will not yet be called. You'll want to choose this index in a way that does not depend on the view loading. Try this before you call scrollToRowAtIndexPath:
NSInteger row = 0;
for (QBCOCustomObject *object in _favouriteResults) {
if (object.userID == self.user.ID) break;
row++;
}
self.highlightedRowIndex = [NSIndexPath indexPathForRow:row inSection:0];
I have a custom UITableViewCell, and when it's selected, it expands and adds a UILabel to the selected cells UIView that I added in the storyBoard.
When I run the app and select a cell, the label gets added to myView as expected. The problem is, when I scroll down, the label is also shown at another cell.
Apparently the reason its behaving like so, is because I'm reusing the cell and I don't clean them as Emilie stated. I'm trying to call the method of prepareForReuse and 'cleaning' the cell, but I'm having trouble doing that. Here is my code:
- (void)prepareForReuse {
NSArray *viewsToRemove = [self.view subviews];
for (UILablel *v in viewsToRemove) {
[v removeFromSuperview];
}
Doing that, cleans even the selected cells label.
- (void)viewDidLoad {
self.sortedDictionary = [[NSArray alloc] initWithObjects:#"Californa", #"Alabama", #"Chicago", #"Texas", #"Colorado", #"New York", #"Philly", #"Utah", #"Nevadah", #"Oregon", #"Pensilvainia", #"South Dekoda", #"North Dekoda", #"Iowa", #"Misouri", #"New Mexico", #"Arizona", #"etc", nil];
self.rowSelection = -1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CategorieCell *customCell = [tableView dequeueReusableCellWithIdentifier:#"cellID" forIndexPath:indexPath];
customCell.title.text = [self.sortedDictionary objectAtIndex:indexPath.row];
return customCell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
CategorieCell *customCell = (CategorieCell *)[tableView cellForRowAtIndexPath:indexPath];
if (self.info) {
[self.info removeFromSuperview];
}
self.info = [[UILabel alloc] init];
[self.info setText:#"Hello"];
[self.info setBackgroundColor:[UIColor brownColor]];
CGRect labelFrame = CGRectMake(0, 0, 50, 100);
[self.info setFrame:labelFrame];
[customCell.infoView addSubview:self.info];
NSLog(#"%ld", (long)indexPath.row);
self.rowSelection = [indexPath row];
[tableView beginUpdates];
[tableView endUpdates];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([indexPath row] == self.rowSelection) {
return 159;
}
return 59;
}
The answer is quite simple : you reuse your cell like you should, but never clean them
Reusing your UITableViewCell means that the cell you clicked on previously will be reused when it will go off-screen.
When clicked, you add a view to your UITableViewCell. When reused, the view is still there because you never remove it.
You have two choices : One, you could set a tag of the self.info view (or check with the indexpath you're keeping in memory), then check when you dequeue the cell if the info view is there, and remove it. The cleaner solution would be to implement the view removal by overriding the prepareForReuse method of your custom UITableViewCell
Precision
The first thing you need to do is set a tag for your self.info view after initializing it:
[self.info setTag:2222];
If you want to keep it as simple as possible, you could check and remove the self.info view directly in your cellForRowAtIndexPath method :
CategorieCell *customCell = [tableView dequeueReusableCellWithIdentifier:#"cellID" forIndexPath:indexPath];
customCell.title.text = [self.sortedDictionary objectAtIndex:indexPath.row];
if [customCell.infoView viewWithTag: 2222] != nil {
[self.info removeFromSuperview]
}
return customCell;
I am not a percent sure this code compiles, I cannot test it on my side for now. Hope it works !
I want to change the color and the text of the button when UITableViewCellEditingStyleDelete, how can I do that? Here's how I call the method for deleting a cell :) Thanks!
(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
if(editingStyle == UITableViewCellEditingStyleDelete){
[self.tasks removeObjectAtIndex:indexPath.row];
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:self.tasks forKey:#"tasks"];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationRight];
[tableView endUpdates];
}
}
What you can do is the following:
-(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Set NSString for button display text here.
NSString *newTitle = #"Remove";
return newTitle;
}
The method call to accomplish this is found in the Apple iOS Dev Docs here
Honestly, I would NOT change the color - the Apple HIG (Human Interface Guidelines) would likely recommend the color stay a consistent red to make sure users don't have a different expectation for your app's behavior.
You can custom your cell. And then, add UISwipeGestureRecognizer for this cell on method cellforRowatindexPath like this:
//custom delete button on cell comment
UISwipeGestureRecognizer * swipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(cellWasSwiped:)];
[swipeRecognizer setDirection:(UISwipeGestureRecognizerDirectionLeft |
UISwipeGestureRecognizerDirectionRight)];
[cell addGestureRecognizer:swipeRecognizer];
Implement cellWasSwiped function:
- (void)cellWasSwiped:(UISwipeGestureRecognizer *)recognizer {
//edit your custom button delete in here.
.....
[self.tableView commitEditingStyle:UITableViewCellEditingStyleDelete forRowAtIndexPath:indexPath];
}
Sorry but I've been stuck with this tricky problem. I have a tableView and once the user clicks it, a checkmark will appear and it is highlighted. However, when the user clicks it again, only the checkmark is gone and the highlight remains. On the third click, the checkmark is gone but I get the highlight. On the fourth click, the tableViewCell is finally cleared. I suspect this has something to do with my didSelectRowAtIndexPath method.
Here is my cellForRowAtIndexPath method.
What I basically do here is that I set the next labels and the checkmark if needed.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *ItemCellIdentifier = #"CellIdentifier";
SearchResultTableViewCell *tableCell =(SearchResultTableViewCell *)[tableView dequeueReusableCellWithIdentifier:ItemCellIdentifier];
//set text labels here
[tableCell.price setText:[NSString stringWithString:[priceList objectAtIndex:indexPath.row]]];
[tableCell.itemName setText:[NSString stringWithString:[itemNameList objectAtIndex:indexPath.row]]];
//set check mark and highlights.
if ([[checkList objectAtIndex:indexPath.row] integerValue] == 1){
tableCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else{
tableCell.accessoryType = UITableViewCellAccessoryNone;
}
return tableCell;
}
Here is my didSelectRowAtIndexPath method. In this method, I toggle the checkMark value by switching it to 0 if it's 1 and vice versa, so when the [self.searchResults reloadData]; gets called, it knows which rows needs the checkmark and which ones do not. I also set the selected cell as selected or not because I save the index path for the selected rows so when I reload the table, I know which ones were selected and I can highlight it.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if ([[checkList objectAtIndex:indexPath.row] integerValue] == 1){
[checkList replaceObjectAtIndex:indexPath.row withObject:#"0"];
[[tableView cellForRowAtIndexPath:indexPath] setSelected:NO];
}
else{
[checkList replaceObjectAtIndex:indexPath.row withObject:#"1"];
[[tableView cellForRowAtIndexPath:indexPath] setSelected:YES];
}
NSArray *indexPaths = [self.searchResults indexPathsForSelectedRows];
//searchResults is my tableView
[self.searchResults reloadData];
for (NSIndexPath *indexPath in indexPaths) {
[self.searchResults selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
}
I have a feeling I'm doing the [[tableView cellForRowAtIndexPath:indexPath] setSelected:NO]; wrong. How do I properly access the tableViewCell from the tableView object and how do I properly set it as selected or not?
Thanks in advance
In your -didSelectRowAtIndexPath:, make sure to call [tableView deselectRowAtIndexPath:indexPath animated:YES].
Change value passed to animated as desired.
Just noticed, I wouldn't set selected manually in -didSelectRowAtIndexPath:. I'd set the cell selected or not only in the configuration of the cell. Take out your call to setSelected: and see if it works.
I think the
[self.searchResults reloadData];
maybe causing the table to be reloaded and then independently figure out if a cell is selected or not. I use this command all the time particularly when there are changes to the underlying array or data, and it maybe important to what you are doing when the row is selected. In which case you amy want to do this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSArray *indexPaths = [self.searchResults indexPathsForSelectedRows];
//searchResults is my tableView
[self.searchResults reloadData];
for (NSIndexPath *indexPath in indexPaths) {
[self.searchResults selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
if ([[checkList objectAtIndex:indexPath.row] integerValue] == 1){
[checkList replaceObjectAtIndex:indexPath.row withObject:#"0"];
[[tableView cellForRowAtIndexPath:indexPath] setSelected:NO];
}
else{
[checkList replaceObjectAtIndex:indexPath.row withObject:#"1"];
[[tableView cellForRowAtIndexPath:indexPath] setSelected:YES];
}
}
I have an iPad app which uses a UISplitViewController (with a UITableView on the left and a detail view on the right). My table view highlights the selected cell in blue when you tap on it.
When I call the following method, the cell is selected but not highlighted in blue:
[self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionTop];
I have spent literally days fiddling about with various delegate methods and hacks trying to get the cell to highlight programatically just as if it had been tapped. I can't do it.
I've managed to almost get there with this:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (shouldHighlightCell)
{
NSIndexPath *indexPathForCellToHighlight = [NSIndexPath indexPathForRow:0 inSection:0];
if ([indexPath isEqual:indexPathForCellToHighlight])
{
cell.selected = YES;
shouldHighlightCell = NO;
}
}
}
It works as long as I also have this (otherwise it remains selected even when another cell is tapped):
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *ip = [NSIndexPath indexPathForRow:0 inSection:0];
if ([[self.tableView cellForRowAtIndexPath:ip] isSelected])
{
[[self.tableView cellForRowAtIndexPath:ip] setSelected:NO];
}
NSIndexPath *iToTheP = indexPath;
return iToTheP;
}
I know this is a weird and convoluted workaround. I wouldn't mind, but it doesn't even work fully. The selected cell loses its highlight if it is scrolled off screen, whereas a cell that has been tapped remains highlighted when scrolled off screen.
I'm absolutely baffled by this. I'm sure this workaround shouldn't even be necessary, that there is a much simpler solution.
Please be sure the cell's selectionStyle is UITableViewCellSelectionStyleBlue and the tableView's allowsSelection is set to YES.
The method selectRowAtIndexPath:animated:scrollPosition: works fine for me. It does highlight the selected cell.
I went through and tried all these and other solutions and no joy. In my case the problem (which drove me nuts for 2 hrs) was the following - shortly after I was calling selectRowAtIndexPath, I was calling reloadData on the tableview. That reload was wiping all the highlighting! Beware of this pitfall! With the unnecessary reloading of data call gone, the highlighting happenned as expected.
I also tried many approaches to get the initial selection to display on my single-selection UITableView. What finally worked for me was to defer the selection of the initial row until the table was set up by calling it in my UITableViewController's viewDidAppear:
override func viewDidAppear(animated: Bool)
{
tableView.selectRowAtIndexPath(indexPathToSelectInitially, animated: false, scrollPosition: .None)
}
I found this and it works for me (aka calling the delegate method didSelectRowAtIndexPath)
NSIndexPath *defaultIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self tableView:[self tableView] didSelectRowAtIndexPath:defaultIndexPath];
PS. I'm using UITableViewController.
I found this to be completely unfixable using all known possibilities. In the end I fixed it by ditching a lot of my code and switching to NSFetchedResultsController instead. NSFetchedResultsController was introduced shortly after I originally wrote this app, and it greatly simplifies the process of using Core Data with UITableViews.
https://developer.apple.com/library/IOs/documentation/CoreData/Reference/NSFetchedResultsController_Class/index.html
It gets the backgroundview with cell border looking like seperator.Do not change the default tableview settings in Interface builder.Make sure UITableViewCellSelectionStyleNone is NOT set to selectionstyle. I am pasting the working code. :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *kCellIdentifier = #"PlayListCell";
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:kCellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:kCellIdentifier];
}
MPMediaPlaylist *playList = [playlistCollection objectAtIndex:indexPath.row];
cell.textLabel.text = playList.name;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
// cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%d Songs",[playList.items count]];
MPMediaItemCollection *playListMediaCollection = [playlistCollection objectAtIndex:indexPath.row ];
cell.imageView.image =[UIImage imageWithCGImage:[self getImageForCollection:playListMediaCollection.items]];
// the main code which make it highlight
UIView *bgColorView = [[UIView alloc] init];
bgColorView.backgroundColor = [UIColor colorWithRed:170.0f/255.0 green:170.0f/255.0 blue:170.0f/255.0 alpha:1.0f];
[bgColorView.layer setBorderColor:[UIColor blackColor].CGColor];
[bgColorView.layer setBorderWidth:1.0f];
[cell setSelectedBackgroundView:bgColorView];
return cell;
}