UITableView on scrolling goes wrong - ios

I have created UITableView on UIView Class.
Based on the selection row setting the alpha value of UIImageView to 1.0f
on deselect the row setting alpha value to 0.2f, which work good.
But on scrolling the selected value (i.e alpha 1.0f) is highlighted with wrong cell, which was not selected at all.
Please find the below code which i have implemented.
Your feedback will be appreciated.
// Code
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [colorNameList count]; // count is century.
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
return [self loadMoreTableViewCellForTableView:tableView indexPath:indexPath];
}
- (FilterColorTableViewCell *)loadMoreTableViewCellForTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath {
FilterColorTableViewCell *cell = (FilterColorTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"FilterColorTableViewCell"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[cell.filterColorImageView setBackgroundColor:[UIColor colorWithHexString:[[[ColorModelClass colorListNames]allValues] objectAtIndex:indexPath.row]alpha:1]];
cell.lbl_FilterColorName.text = [colorNameList objectAtIndex:indexPath.row];
cell.lbl_FilterColorCount.text = [NSString stringWithFormat:#"Items: %ld",(long)indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
{
FilterColorTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
self.filterColorTableView.allowsMultipleSelection = YES;
cell.filterSelectionColor.alpha = (cell.selected ?1.0f:0.2f);
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
FilterColorTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.filterSelectionColor.alpha = (cell.selected ?1.0f:0.2f);
}
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return UITableViewAutomaticDimension;
}

You should also use this line of code:
cell.filterSelectionColor.alpha = (cell.selected ?1.0f:0.2f);
in your
- (FilterColorTableViewCell *)loadMoreTableViewCellForTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath {
because it reuses the cell and this is why your previous settings are not reset.

If I understood you correctly, cell.filterSelectionColor.alpha is not correct as soon as you scroll through the TableView, isn't it?
You are relying on the Cell selected property, though cell position may not be the same as when they were created when scrolling. You should store the selected cells somewhere else (an array or so) and refresh Cell's status in cellForRowAtIndexPath. Something like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
return [self loadMoreTableViewCellForTableView:tableView indexPath:indexPath];
}
- (FilterColorTableViewCell *)loadMoreTableViewCellForTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath {
FilterColorTableViewCell *cell = (FilterColorTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"FilterColorTableViewCell"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[cell.filterColorImageView setBackgroundColor:[UIColor colorWithHexString:[[[ColorModelClass colorListNames]allValues] objectAtIndex:indexPath.row]alpha:1]];
cell.lbl_FilterColorName.text = [colorNameList objectAtIndex:indexPath.row];
cell.lbl_FilterColorCount.text = [NSString stringWithFormat:#"Items: %ld",(long)indexPath.row];
// selectedItems is an array of booleans with as many elements as the TableView
cell.filterSelectionColor.alpha = self.selectedItems[indexPath.row] ? 1.0f : 0.2f;
return cell;
}

When tableView reloads it uses the same cell instance and changes the data. When you reload/scroll your cellForRowAtIndexpath method is called and over there you will have to specify which cell should have which alpha. Below change in your code is required :
- (FilterColorTableViewCell *)loadMoreTableViewCellForTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath {
FilterColorTableViewCell *cell = (FilterColorTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"FilterColorTableViewCell"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[cell.filterColorImageView setBackgroundColor:[UIColor colorWithHexString:[[[ColorModelClass colorListNames]allValues] objectAtIndex:indexPath.row]alpha:1]];
cell.lbl_FilterColorName.text = [colorNameList objectAtIndex:indexPath.row];
cell.lbl_FilterColorCount.text = [NSString stringWithFormat:#"Items: %ld",(long)indexPath.row];
// Set alpha here
cell.filterSelectionColor.alpha = (cell.selected ?1.0f:0.2f);
return cell;
}

create an int property in your controller
NSMutableArray *selectedCells;
initialize the variable..
- (void)viewDidload {
...
...
selectedCells = [NSMutableArray array];
}
set the value on selection and deselection..
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
{
...
...
[selectedCells addObject:[NSNumber numberWithInt:indexPath.row]];
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
...
...
for (int i=0;i<selectedCells.count;i++) {
if([selectedCells[i] intValue] == indexPath.row)
[selectedCells removeObjectAtIndex:i];
}
}
As the cells are reused by the tableView.. you need to setup the cell from the cellForRow method..
- (FilterColorTableViewCell *)loadMoreTableViewCellForTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath {
FilterColorTableViewCell *cell = (FilterColorTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"FilterColorTableViewCell"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
...
...
BOOL selected = [selectedCells containsObject:[NSNumber numberWithInt:indexPath.row]];
cell.filterSelectionColor.alpha = (selected) ?1.0f:0.2f;
return cell;
}

Related

How to prevent overflow of adjustable height tableview cell on delete

In a UITableView Controller, I have just added 'swipe to delete' by implementing tableView: commitEditingStyle: forRowAtIndexPath. Additionally, the rows can be selected to expand showing more content.
The undesired result after swiping:
The two lower rows remain in view after swiping until about about 0.5 seconds after the undelete animation completes.
A screenshot of IB:
The cell's contents have grown into the lower cell without it showing that it has been selected. (Selection causes the cell to increase height and give it a grayish background color.) This is occurring on every row in 2 similarly operating view controllers.
I have tried (without success) to intercept the 'selection' in several UITableViewDelegate methods, and cannot find out how to stop this from occurring. I have also tried setting the IB dynamic prototype cells to height: 85.
Looking for ideas on how to prevent this expansion from occurring.
EDIT
- (void)viewDidLoad {
....
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = kCellHeight;
....
}
#pragma mark - TableView delegate
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[self.fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
NSInteger *rows = (NSInteger *)[sectionInfo numberOfObjects];
if (!self.rowsInSection)
self.rowsInSection = rows;
if (rows > 0)
return [sectionInfo numberOfObjects];
else {
[tableView setSeparatorColor:[UIColor clearColor]];
[tableView setBounces:NO];
return 1;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *identifier = self.rowsInSection > 0 ? #"numberIdentifier" : #"noNumbersIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
if (self.rowsInSection > 0)
[self configureCell:cell atIndexPath:indexPath];
else
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// [self.arrayOfIndexPaths addObject:indexPath];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
if (selectedIndexPath) {
if (tableView.editing)
return 85.0;
else if (selectedIndexPath.row == indexPath.row)
return 185.0;
}
return 85.0;
}
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)path {
if (tableView.editing)
return nil;
// If real rows exist, return the path, making row selectable
if (self.rowsInSection > 0)
return path;
// Otherwise do not allow the row to be selected
return nil;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][0];
if ([sectionInfo numberOfObjects] > 0)
// Return the contentView to stop the header from sliding with delete
return [tableView dequeueReusableCellWithIdentifier:#"numberHeaderIdentifier"].contentView;
else
return [tableView dequeueReusableCellWithIdentifier:#"emptyHeaderIdentifier"];
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 75;
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
Number *aNumber = [self.fetchedResultsController objectAtIndexPath:indexPath];
[cell configureSubviewsInCell:cell withNumber:aNumber];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView beginUpdates];
[tableView endUpdates];
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
[context deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];
}
}
You should set the hidden property of the labels that you don't want to show when the table view cell is not selected. For example:
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
Number *aNumber = [self.fetchedResultsController objectAtIndexPath:indexPath];
UILabel *label1 = (UILabel *)[cell.contentView viewWithTag:501];
label1.text = [aNumber valueForKey:#"number"];
if (!cell.selected)
{
label1.hidden = YES;
}
else
{
label1.hidden = NO;
}
.....
}
Then in didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView beginUpdates];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UILabel *label1 = (UILabel *)[cell.contentView viewWithTag:501];
label1.text = [aNumber valueForKey:#"number"];
label1.hidden = NO;
[tableView endUpdates];
}
You should look into subclassing UITableViewCell so you don't have to use tags to access subviews.
The 'hiding' solution posted by beowulf is a valid option. In addition and because the swipe (to begin editing) was causing subviews in the cell to become 'unclipped', a method needed to be overrided, like so:
// this method is called as the swipe to delete is started
- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
// only hide for unexpanded (unselected) cells
if ([self.selectedRowIndex compare:indexPath] != NSOrderedSame)
{
NumberTableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
// a cell subclass method to hide/unhide subviews that fall into
// the next cell below
[cell subViewsInCellShouldBeHidden:YES];
}
}

iOS UITableViewCell Have To Hold A Long Press To Select Item

So this is driving me nuts, whenever I tap an item in my UITableView it does nothing, but when i press and hold the UITableViewCell after about 3-5 seconds it decides to move forward and do what I want.. any thoughts why this might be happening?
Here's my code
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 100;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
_cell = [_arrayItems objectAtIndex:indexPath.row];
_cell = nil;
static NSString *AutoCompleteRowIdentifier = #"AutoCompleteRowIdentifier";
_cell = (CustomWidget *)[tableView dequeueReusableCellWithIdentifier:AutoCompleteRowIdentifier];
if (_cell == nil) {
_cell = [[CustomWidget alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:AutoCompleteRowIdentifier title:[_arrayItems objectAtIndex:indexPath.row] subTitle:#"Custom subtitle"];
}
_cell.textLabel.text = [_arrayItems objectAtIndex:indexPath.row];
_cell.textLabel.hidden = YES;
return _cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return _arrayItems.count;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
_passedInPageTitle = selectedCell.textLabel.text;
[self openDetailPage];
}
I found my answer here - I had a UITapGestureRecognizer on the UITableView's parent view, which was capturing the tap.

Being able to tap on ONLY one item in a UITableView

So I have a subclassed UITableView that lists data. I need to make only one cell selectable.
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// rows in section 0 should not be selectable
UITableViewCell *cell = (UITableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
if (indexPath.row == 3) {
cell.userInteractionEnabled = YES;
cell.selectionStyle = UITableViewCellSelectionStyleGray;
NSLog(#"Hey whats up, address");
return indexPath;
}
else {
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
return nil;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
My code that does this so far works, but only after the cell is clicked at least once. Placing it in didSelectCell allows the cell to be selected if held down for 1-2 seconds.
You should do that in the cellForRowAtIndexPath. Like this:
-(UITableViewCell*)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// your code
if(indexPath.row != 3)
{
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
{
}
And then on didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if(indexPath.row == 3)
{
//do your stuff
{
}

i want to number my rows in a UITableView

im using core data i have an entity called questions whenever i add my question to my table i want them to display the number of the question (kind of like auto increment thing)
can anyone pls help me out
thanks
here is my code if its relevant
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.questionArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
// Configure the cell...
questionObject = [self.questionArray objectAtIndex:indexPath.row];
cell.textLabel.text = questionObject.questionDescription;
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (nil == cell) {
cell = ...; //create a cell instance if it wasn't found in reusable cache
}
// Configure the cell...
questionObject = [self.questionArray objectAtIndex:indexPath.row];
NSString *cellText = [NSString stringWithFormat:#"%d. %#", indexPath.row+1, questionObject.questionDescription];
cell.textLabel.text = cellText;
return cell;
}

UITableView reloadRowsAtIndexPaths graphical glitch

If I call reloadRowsAtIndexPaths for the first cell of a section, with previous section empty and the one above not-empty, I get a strange animation glitch (even if I specify "UITableViewRowAnimationNone") where the reloaded cell slides down from the above section..
I tried to simplify the example as much as possible:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0)
return 1;
else if (section == 1)
return 0;
else if (section == 2)
return 3;
return 0;
}
- (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] autorelease];
}
// Configure the cell...
cell.textLabel.text = #"Text";
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *editedCell = [[NSArray alloc] initWithObjects:indexPath, nil];
//[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:editedCell withRowAnimation:UITableViewRowAnimationNone];
//[self.tableView endUpdates];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return #"Section";
}
Actually you can comment out the last method, but it gives a better understanding of the problem.
You can set values you want to the cell directly, not letting table to reload itself (and thus avoiding any unwanted animations). Also to make code clearer and avoid code duplication lets move cell setup to a separate method (so we'll be able to call it from different locations):
- (void) setupCell:(UITableViewCell*)cell forIndexPath:(NSIndexPath*)indexPath {
cell.textLabel.text = #"Text"; // Or any value depending on index path
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[self setupCell:cell forIndexPath:indexPath];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// create cell
// Configure the cell...
[self setupCell:cell forIndexPath:indexPath];
return cell;
}

Resources