First of all: I know that some people already posted topics like that, but nobody gave a clear answer in all those topics.
I have a settings-UITableView in my application. Now i want to add a TableViewCell where i can choose between some numbers with a UIPickerView.
In the tableView didSelectRowAtIndexPath method i created the if statement for the right cell
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.row == 1){
}
}
How can i add a UIPickerView for this cell? It should slide up from the bottom and it would be nice if there is something like a "done" button.
Have you seen the sample program released with iOS 7 called DateCell? It uses a UIDatePicker, but I found it pretty straightforward to adapt it to a regular UIPickerView.
It does exactly what you're describing: edit a UITableViewCell with a picker that opens directly under the row you're editing.
This is also based on your other question, so I am including those functionalities here as well (i.e. the switch).
In your YourTableViewController.h
set:
#interface YourTableViewViewController : UITableViewController <UIPickerViewDataSource, UIPickerViewDelegate>
In your YourTableViewController.m
Paste this code:
#interface YourTableViewViewController ()
#property NSInteger toggle;
#property (strong, nonatomic) UIPickerView *pickerView;
#end
#implementation YourTableViewViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.toggle = 0;
self.pickerView = [[UIPickerView alloc] initWithFrame:(CGRect){{0, 0}, 320, 480}];
self.pickerView.delegate = self;
self.pickerView.dataSource = self;
self.pickerView.center = (CGPoint){160, 640};
self.pickerView.hidden = YES;
[self.view addSubview:self.pickerView];
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 2;
}
- (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];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
if(indexPath.row == 0)
{
[cell.contentView addSubview:self.mySwitch];
}
if(indexPath.row == 1)
{
cell.textLabel.textColor = [UIColor darkGrayColor];
if(self.toggle == 0)
{
cell.textLabel.text = #"Choose a number";
}
else
{
cell.textLabel.text = #"Cancel";
}
}
// Configure the cell...
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == 1)
{
if(self.toggle == 0)
{
self.toggle = 1;
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:YES];
[self bringUpPickerViewWithRow:indexPath];
}
else
{
self.toggle = 0;
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:YES];
[self hidePickerView];
}
}
}
- (void)bringUpPickerViewWithRow:(NSIndexPath*)indexPath
{
UITableViewCell *currentCellSelected = [self.tableView cellForRowAtIndexPath:indexPath];
[UIView animateWithDuration:1.0f
delay:0.0f
options:UIViewAnimationOptionCurveEaseInOut
animations:^
{
self.pickerView.hidden = NO;
self.pickerView.center = (CGPoint){currentCellSelected.frame.size.width/2, self.tableView.frame.origin.y + currentCellSelected.frame.size.height*4};
}
completion:nil];
}
- (void)hidePickerView
{
[UIView animateWithDuration:1.0f
delay:0.0f
options:UIViewAnimationOptionCurveEaseInOut
animations:^
{
self.pickerView.center = (CGPoint){160, 800};
}
completion:^(BOOL finished)
{
self.pickerView.hidden = YES;
}];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
self.toggle = 0;
[self.tableView reloadData];
[self hidePickerView];
NSLog(#"row selected:%ld", (long)row);
}
- (NSString*) pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return [NSString stringWithFormat:#"%d", row+1];
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return 10;
}
#end
Tested.
Addendum:
Also, in your storyboard, change the separator for YourTableView to None (looks better in your case here).
Table View Separator:
in viewDidLoad, add:
self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
And in bringUpPickerViewWithRow
after:
UITableViewCell *currentCellSelected = [self.tableView cellForRowAtIndexPath:indexPath];
add:
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.tableView setNeedsDisplay];
And lastly, in hidePickerView, add:
self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
[self.tableView setNeedsDisplay];
Create custom ViewController that include UIPickerView and Done
button.
Add it as subview on your tableview. (Place it bottom so
that it does not visible).
Once user click appropriate cell, you
can animate picker-view from bottom.
Once user select an item
animate and position it to bottom.
I have done above steps for same purpose. If you want I can send custom controller that include UIPickerView and done button.
Related
How top expand collapse custom cell tableview and expanding the cell must be dynamic height in iOS objective c?
viewcontroller having custom tableview cells when click on the cell,cell must be expand/collapse having one view and display data in that view and height must be dynamic
You'll have to maintain a state (expanded/not expanded) for the custom table view cell. Every time it's tapped you make the necessary changes in the UI and toggle the state. You can then call
reloadData()
or
-(void)reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths
withRowAnimation:(UITableViewRowAnimation)animation;
You can also calculate and set the new height of the cell and the reload function will take care of the animation.
You used tableview then easy manage expand and collapse custom cell tableview and expanding with animation.
Follow code for expand and collapse.
.h File
BOOL currentlyExpanded;
NSMutableIndexSet *expandedSections;
.m File
- (void)viewDidLoad
{
if (!expandedSections)
{
expandedSections = [[NSMutableIndexSet alloc] init];
}
}
Use Tableview Delegate and Datasource method..
#pragma mark - Tableview Delegate -
- (BOOL)tableView:(UITableView *)tableView canCollapseSection:(NSInteger)section
{
return YES;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([self tableView:tableView canCollapseSection:section])
{
if ([expandedSections containsIndex:section])
return 6; //return your array count..
else
return 1;
}
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier]
;
}
if ([self tableView:tableView canCollapseSection:indexPath.section])
{
//Display your dynamic cell contain..
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self tableView:tableView canCollapseSection:indexPath.section])
{
NSInteger section = indexPath.section;
currentlyExpanded = [expandedSections containsIndex:section];
NSInteger rows;
if (currentlyExpanded)
{
rows = [self tableView:tableView numberOfRowsInSection:section];
[expandedSections removeIndex:section];
}
else
{
[expandedSections addIndex:section];
rows = [self tableView:tableView numberOfRowsInSection:section];
}
// Animation when cell expand and collapse
if(currentlyExpanded)
{
[tableView deleteRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationTop];
CGFloat startRadians, endRadians;
startRadians = M_PI/2;
endRadians = 0.0f;
btnArrow.layer.affineTransform = CGAffineTransformMakeRotation(startRadians);
[UIView animateWithDuration:0.3f animations:^{
btnArrow.layer.affineTransform = CGAffineTransformMakeRotation(endRadians);
}completion:^(BOOL finished){
}];
}
else
{
[tableView insertRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationTop];
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
[btnArrow setTransform:CGAffineTransformRotate(btnArrow.transform, M_PI/2 )];
}completion:^(BOOL finished){
}];
}
}
}
So i have been trying for a little while now to create a table view with expandable sections and one non expandable section. One of the expandable sections should have 3 text fields inside them in which you can edit the test inside the text field. I was able to get that working bt the moment you collapse the section and expand it again the textfield suddenly duplicates itself above and sometimes swaps itself out with the above cell. Ihavent been able to figure out why or how to make it not do that.
The idea is when the user enters text in the field and selects enter the text is stored into an array.
the code:
- (void)viewDidLoad{
[super viewDidLoad];
if (!expandedSections){
expandedSections = [[NSMutableIndexSet alloc] init];
}
manualSensorName = [[NSMutableArray alloc]initWithObjects: #"Sensor",#"",#"2",#"T", nil];
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Expanding
- (BOOL)tableView:(UITableView *)tableView canCollapseSection:(NSInteger)section{
if (section>0) return YES;
return NO;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if ([self tableView:tableView canCollapseSection:section])
{
if ([expandedSections containsIndex:section])
{
return 5; // return rows when expanded
}
return 1; // only top row showing
}
// Return the number of rows in the section.
return 1;
}
- (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];
}
// Configure the cell...
if ([self tableView:tableView canCollapseSection:indexPath.section]){
if (!indexPath.row){
// first row
cell.textLabel.text = #"Expandable"; // only top row showing
if ([expandedSections containsIndex:indexPath.section])
{
UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"arrowUP.png"]];
cell.accessoryView = arrow;
}
else
{
UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"arrowDOWN.png"]];
cell.accessoryView = arrow;
}
}
else {
if (indexPath.row == 1){
NSString *flightNumText = [manualSensorName objectAtIndex:indexPath.row];
cell.textLabel.text = flightNumText;
}
else if (indexPath.row == 2){
txtManualSensor = [[UITextField alloc] initWithFrame:CGRectMake(180, 5, 120, 30)];
txtManualSensor.placeholder = #"Select";
txtManualSensor.delegate = self;
txtManualSensor.autocorrectionType = UITextAutocorrectionTypeNo;
txtManualSensor.backgroundColor = [UIColor whiteColor];
[txtManualSensor setBorderStyle:UITextBorderStyleBezel];
[txtManualSensor setTextAlignment:NSTextAlignmentCenter];
[txtManualSensor setReturnKeyType:UIReturnKeyDone];
// UITextField *playerTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 5, 120, 30)];
// playerTextField.adjustsFontSizeToFitWidth = YES;
// playerTextField.textColor = [UIColor blackColor];
// playerTextField.placeholder = #"SAMPLE";
// playerTextField.tag = 200;
// playerTextField.delegate = self;
// [cell.contentView addSubview:playerTextField];
cell.textLabel.text = #"Sensor Name";
[cell addSubview:txtManualSensor];
}
else if (indexPath.row == 3){
cell.textLabel.text = #"Some Detail";
cell.accessoryView = nil;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
}
else {
cell.accessoryView = nil;
cell.textLabel.text = #"Normal Cell";
}
return cell;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
[manualSensorName replaceObjectAtIndex:2 withObject:textField.text];
return YES;
}
-(BOOL) textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if ([self tableView:tableView canCollapseSection:indexPath.section]){
if (!indexPath.row){
[tableView beginUpdates];
// only first row toggles exapand/collapse
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSInteger section = indexPath.section;
BOOL currentlyExpanded = [expandedSections containsIndex:section];
NSInteger rows;
NSMutableArray *tmpArray = [NSMutableArray array];
if (currentlyExpanded) {
rows = [self tableView:tableView numberOfRowsInSection:section];
[expandedSections removeIndex:section];
}
else {
[expandedSections addIndex:section];
rows = [self tableView:tableView numberOfRowsInSection:section];
}
for (int i=1; i<rows; i++) {
NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i inSection:section];
[tmpArray addObject:tmpIndexPath];
}
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (currentlyExpanded) {
UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"arrowDOWN.png"]];
[tableView deleteRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationFade];
cell.accessoryView = arrow;
}
else {
UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"arrowUP.png"]];
[tableView insertRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationFade];
cell.accessoryView = arrow;
}
NSLog(#"tableview row is %ld in section %ld",(long)indexPath.row,(long)indexPath.section);
[tableView endUpdates];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(#"selected row is %ld in section %ld",(long)indexPath.row,(long)indexPath.section);
if (indexPath.row == 1) {
// update text fields in cell table view
}
}
}
It may be as simple as replacing UITableViewRowAnimationTop by UITableViewRowAnimationFade:
When changing indexes in didSelectRowAtIndexPath, UITableViewCells change physical location (remember that the UITableView is a UIScrollView), and the scroller can't keep track of what your intent is.
UITableViewRowAnimationTop attempts to adjust the scrolling location, but fails.
Other design considerations:
Do not mix the model (the array of data to be displayed) with your view model (the UI displaying the model). In didSelectRowAtIndexPath, you should first re-order your model, then apply it to the cells
Consider not changing indexes on the fly: you may prefer a model that actually reflects the view structure, i.e. a tree.
Have you noticed you are not respecting - (void)tableView:(UITableView *)tableView and sometimes using self tableView:tableView or self.customTableView in the same method? You should use the tableView passed to you.
I have two table views in one viewController and a menu button.
Initially only tableView1 is displayed, when I press menu button the second table view should appear and the tableView1 is still there.
I was reading about and I implemented what I found, but without results.
Both table view appears, but data are the same and I don't want this. I was trying to do like this :
- (void) viewDidLoad {
tableView.hidden = NO;
tableViewMenu.hidden = YES;
tableView.delegate = self;
tableView.dataSource = self;
tableViewMenu.delegate = self;
tableViewMenu.dataSource = self;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == tableView) {
return 30;
}
else {
return 4;
}
}
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == tableView) {
static NSString *CellIdentifier1 = #"Cell1";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1] ;
}
cell.textLabel.text = #"Table 1";
NSLog(#"1here is%i %#",indexPath.row,cell.textLabel.text);
return cell;
} else {
static NSString *CellIdentifier2 = #"Cell2";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2] ;
}
cell.textLabel.text = #"Table 2";
return cell;
}
}
int i = 1;
- (void) showMenu {
//slide the content view to the right to reveal the menu
//tableView.hidden = NO;
tableViewMenu.hidden = NO;
NSLog(#"Display");
if (i == 1) {
[UITableView animateWithDuration:.25
animations:^{
[tableView setFrame:CGRectMake(tableViewMenu.frame.size.width, tableView.frame.origin.y, tableView.frame.size.width, tableView.frame.size.height)];
[testView setFrame:CGRectMake(tableViewMenu.frame.size.width, testView.frame.origin.y, testView.frame.size.width, testView.frame.size.height)];
}];
i = 0;
} else {
[UIView animateWithDuration:.25
animations:^{
[tableView setFrame:CGRectMake(0, tableView.frame.origin.y, tableView.frame.size.width, tableView.frame.size.height)];
[testView setFrame:CGRectMake(0, testView.frame.origin.y, testView.frame.size.width, testView.frame.size.height)];
tableViewMenu.hidden=YES;
}];
i = 1;
}
}
I guess the problem is the line :
if(tableView==tableView)
You should compare the tableview arguments with your #property.
If both the arguments and the iVar have the same name, the argument will override your iVar in the method scope.
if (tableview == self.tableView)
I set for tableview a tag and i did this :
if (tableView.tag==0) {
return 30;
}
else { return 4;
}
}
Idem is for cellForRowAtIndexPath
You have to have 2 table views:
#property (nonatomic, weak) IBOutlet UITableView* firstTableView;
#property (nonatomic, weak) IBOutlet UITableView* secondTableView;
When you press menu button you should change the delegate like this:
self.firstTableView.hidden = FALSE;
self.secondTableView.hidden = TRUE;
[self.firstTableView reloadData]
self.firstTableView.dataSource = self;
self.firstTableView.delegate = self;
or
self.firstTableView.hidden = TRUE;
self.secondTableView.hidden = FALSE;
[self.secondTableView reloadData]
self.secondTableView.dataSource = self;
self.secondTableView.delegate = self;
And in TableView Data Source:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == self.firstTableView) {
...
}
} else if (tableView == self.secondTableView){
...
}
And
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.firstTableView) {
return 30;
} else if (tableView == self.secondTableView){
return 4;
}
I'm attempting to create an inline DatePicker inside a TableView cell, similar to this and this SO thread.
I create the date picker using the method below, which is called when the view is loaded:
- (void)createDatePicker{
_datePicker = [[UIDatePicker alloc]init];
_datePicker.datePickerMode = UIDatePickerModeTime;
_datePicker.clipsToBounds = YES;
_datePicker.backgroundColor = [UIColor colorWithRed:0.922 green:0.937 blue:0.949 alpha:1];
NSLog(#"date picker created");
}
I then check to see if the bottom row of the third section in my table view is selected. If it is, and the date picker already isn't showing, then I call the method to show the date picker's cell:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == HourTimeZoneRow && self.datePickerIsShowing == NO)
{
NSLog(#"Time of day section");
[self showDatePickerCell];
} else
{
[self hideDatePickerCell];
}
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
Below are the methods to show the date picker's cell:
- (void)showDatePickerCell {
[self.tableView addSubview:_datePicker];
self.datePickerIsShowing = YES;
self.datePicker.hidden = NO;
[self.tableView reloadData];
NSLog(#"Show date picker");
}
...and hide the cell:
- (void)hideDatePickerCell {
self.datePickerIsShowing = NO;
self.datePicker.hidden = YES;
[self.tableView reloadData];
NSLog(#"Hide date picker");
}
Below is the method to determine if the table view needs to add an extra cell to display the UIDatePicker.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
switch (section) {
case TableSectionOne:
return TotalRowsSection1;
break;
case TableSectionTwo:
return TotalRedZoneRows;
break;
case TableSectionThree:
if (self.datePickerIsShowing == YES) {
return TableSectionThree + 1;
}
else {
return TableSectionThree;
}
break;
default:
return 0;
break;
}
}
Finally, the method below is what is supposed to determine the height of the date picker's cell:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat rowHeight = self.tableView.rowHeight;
if (indexPath.row == HourTimeZoneRow){
rowHeight = 164;
}
else {
rowHeight = self.tableView.rowHeight;
}
return rowHeight;
}
However, what's happening is that when the last row of the third section is selected, the date picker is displayed in the first row of the first section. Does anyone have any suggestions on what I'm doing wrong?
You're adding the datePicker to the tableView, not to a cell within the tableView.
Remove this line from showDatePickerCell:
[self.tableView addSubview:_datePicker];
Then add it (or unhide it) within the proper cell within cellForItemAtIndexPath.
(something like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if (indexPath.row == HourTimeZoneRow) {
// show the datePicker here
}
cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
return cell;
}
)
I have a UITableView in which I need to programmatically select a cell if the data model says that the cell represents the selected choice in a list of items. I do this when I'm configuring the UITableViewCell:
if (group == self.theCase.assignedGroup) {
[self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
self.selectedIndexPath = indexPath;
} else {
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
I am seeing very odd behavior with this. If the first row of the tableview is the one that should be selected, the cell doesn't highlight its background properly. However, if the second row is the one that should be selected, it works as it's supposed to (screenshots at the end).
UPDATE: It could have something to do with the fact that I am loading data for the table asynchronously, and while the data is loading I show a different kind of cell with a progress indicator in that first row. Here's the table view data source code that's handling this:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
if (self.hasMorePages) {
return self.groups.count + 1;
}
return self.groups.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
if (indexPath.row < self.groups.count) {
cell = [tableView dequeueReusableCellWithIdentifier:#"DSAssignCell" forIndexPath:indexPath];
[self configureCell:cell forRowAtIndexPath:indexPath];
} else {
cell = [tableView dequeueReusableCellWithIdentifier:#"DSLoadingCell" forIndexPath:indexPath];
[self configureLoadingCell:cell forRowAtIndexPath:indexPath];
}
return cell;
}
- (void)configureCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath
{
DSGroup *group = self.groups[indexPath.row];
if (group == self.theCase.assignedGroup) {
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
self.selectedIndexPath = indexPath;
} else {
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
cell.textLabel.text = group.name;
cell.tag = kDataCellTag;
}
- (void)configureLoadingCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath
{
UIActivityIndicatorView *activityIndicator;
if ([cell viewWithTag:kActivityIndicatorTag]) {
activityIndicator = (UIActivityIndicatorView *)[cell viewWithTag:kActivityIndicatorTag];
} else {
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityIndicator.center = cell.center;
activityIndicator.tag = kActivityIndicatorTag;
[cell.contentView addSubview:activityIndicator];
}
[activityIndicator startAnimating];
cell.tag = kLoadingCellTag;
}
UPDATE As requested, here is the code that handles the asynchronous loading of the group & agent data from the web service:
- (void)viewDidLoad
{
[super viewDidLoad];
[self resetData];
[self loadData];
}
- (void)resetData
{
self.currentPage = 0;
self.hasMorePages = YES;
self.groups = [[NSMutableArray alloc] initWithCapacity:kGroupsPerPage];
self.agents = [[NSMutableArray alloc] initWithCapacity:kAgentsPerPage];
}
- (void)loadData
{
if (self.showingGroups) {
[DSGroup fetchGroupsOnPage:self.currentPage + 1 perPage:kGroupsPerPage success:^(NSArray *groups, NSDictionary *links, NSNumber *totalEntries) {
[self.groups addObjectsFromArray:groups];
[self didLoadDataPage:(links[#"next"] != [NSNull null])];
} failure:^(NSError *error) {
[self showAlert:#"Could not load groups. Please try again later." withError:error];
}];
} else {
[DSUser fetchUsersOnPage:self.currentPage + 1 perPage:kAgentsPerPage success:^(NSArray *users, NSDictionary *links, NSNumber *totalEntries) {
[self.agents addObjectsFromArray:users];
[self didLoadDataPage:(links[#"next"] != [NSNull null])];
} failure:^(NSError *error) {
[self showAlert:#"Could not load users. Please try again later." withError:error];
}];
}
}
- (void)didLoadDataPage:(BOOL)hasMorePages
{
self.hasMorePages = hasMorePages;
self.currentPage++;
[self.tableView reloadData];
}
Here's a screenshot of trying to select (and highlight) the first row, which is wrong (no gray background):
Here's a screenshot of trying to select (and highlight) the second row, which is correct:
Any idea what might be going on here?
I wasn't able to fix this using the built-in selection styles of UITableViewCell, but subclassing it and overriding setSelected:animated fixed it:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
self.contentView.backgroundColor = selected ? [UIColor grayColor] : [UIColor whiteColor];
}