I have a tableView, with custom cells.
In each cell i have a UIButton. When i click the button inside the cell i want that cell to highlight, but when i click o the cell i don't want this to happen.
Do you know any way to do this?
thank you
until now i have this code:
- (IBAction)buttonMethod: (id)sender {
UIButton *b = (UIButton *) sender;
UITableViewCell *cell = (UITableViewCell *)[[[sender superview] superview] superview];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
[cell setSelected:YES animated:YES];
}
but the cell is highlighted also in -didSelectRow.
- (UITableViewCell *)tableView: (UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"CustomCell";
CustomCell *cell = (CustomCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
NSAssert(cell, #"cell -> nil");
NSDictionary *cellData = [_data objectAtIndex:indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
[cell populateCellWithData:cellData];
return cell;
}
Use this UITableViewDelegate method:
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
return nil;
}
This way, cells can't be selected when the user taps on them, but you can still select them programatically.
Also using
selectRowAtIndexPath:animated:scrollPosition:
on your UITableView , instead of setSelected:animated: on UITableViewCell might be better. Cells can be reused and the selection will probably disappear when it happens.
You have to add following line in tableView delegate method cellForRowATIndexPath.
cell.selectionStyle =- UITableViewCellSelectionStyleNone;
You have to set cell.selectionStyle = UITableViewCellSelectionStyleNone; in cellForRowAtIndexPath method of tableView.
So you can set this style in - (IBAction)buttonMethod: (id)sender. You can add this line at the end. See below:
- (IBAction)buttonMethod: (id)sender {
UIButton *b = (UIButton *) sender;
UITableViewCell *cell = (UITableViewCell *)[[[sender superview] superview] superview];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
[cell setSelected:YES animated:YES];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
Just use UITableViewDelegate like this
-(BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath{
return NO;
}
but If I were you, I would change the background color of cell in [buttonMethod:] with UITableViewCellSelectionStyleNone
Related
I have used custom UITableViewCell. I have added a Gesture in it for swipe option, I have 20 cells in my tableView. If I swipe my first cell and scroll means my 11th cell also updated into my first cell value.
the following is my code snipet.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = (CustomCell*)
[tableView dequeueReusableCellWithIdentifier:#"CustomCellId”];
[cell setRequestCellDelegate:self];
[cell.swipeLeft addTarget:self action:#selector(swipeLeftAction:)];
cell.tag = indexPath.row;
cell.swipeLeft.delegate = self;
cell.swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
cell.indexpath = indexPath;
[cell.swipeRight addTarget:self action:#selector(swipeRightAction:)];
cell.swipeRight.delegate = self;
cell.swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
cell.tableHoldButtn.tag = indexPath.row;
return cell;
}
Please help to find the solution for this.
This is happenning because as soon as your first swiped cell goes off the screen it's being put into queue for reuse. Then when your 10th cell should come on the screen it's not being created but rather 1st cell is being reused. And since you have swiped it, it will be dequeued in exact same state as it left the screen.
You should track changes in table view controller which cell should be swiped and restore that state in your cellForIndexPath data source method.
I think its better to use tableView delegate methods instead on applying gesture. you can use
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;
Additionally you can also customise the edit button appearance by:
-(NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath;
CustomCell *cell = (CustomCell*)
[tableView dequeueReusableCellWithIdentifier:[NSString stringwithFormat:"%ld",indexPath.row]];
reuse Identifier change to the string of indexPath.row
I hope my experiment can help you
note: do not register cell in other place,remove register cell in other place (maybe in viewdidLoad )
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// CustomCell *cell = (CustomCell*)
// [tableView dequeueReusableCellWithIdentifier:#"CustomCellId”];
// need not register cell in other ,like viewdidLoad
CustomCell* cell = [tableView dequeueReusableCellWithIdentifier:[NSString stringWithFormat:#"%#",indexPath.row]];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:[NSString stringWithFormat:#"%#",indexPath.row]];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
[cell setRequestCellDelegate:self];
[cell.swipeLeft addTarget:self action:#selector(swipeLeftAction:)];
cell.tag = indexPath.row;
cell.swipeLeft.delegate = self;
cell.swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
cell.indexpath = indexPath;
[cell.swipeRight addTarget:self action:#selector(swipeRightAction:)];
cell.swipeRight.delegate = self;
cell.swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
cell.tableHoldButtn.tag = indexPath.row;
return cell;
}
I use storyboard and Auto Layout. I add UISwitch to my cell with tag 5. When I choose first UISwitch and scroll down I see that other UISwitch is also turned on and if I scroll up my first UISwitch is turned off. How to fix this?
My code:
- (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];
}
UISwitch* switchView = (UISwitch *)[cell viewWithTag:5];
[switchView addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
return cell;
}
This is because UITableView reuse UITableViewCell so one cell can be use more than once in different indexPaths, in this situation its your responsibility to maintain the state of UITableViewCell subViews. Better place to do this is cellForRowAtIndexPath where you are returning cell add logic to make show/hide UISwitch or to select accurate state i.e. on or off, you can keep that flag in dataSource object and then you can check for that flag to make set right state for UISwitch
Try This:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellSetting";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = [self.settingsArray objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
if ([[self.settingsArray objectAtIndex:indexPath.row] isEqualToString:ROW_PRIVATE_BROWSING])
{
self.privateBrowsingSwitch =[[UISwitch alloc]initWithFrame:CGRectMake(cell.frame.size.width-65, 10, 30, 30)];
if (ApplicationDelegate.privateBrowsing)
{
[self.privateBrowsingSwitch setOn:YES animated:YES];
}
[self.privateBrowsingSwitch addTarget:self action:#selector(changeSwitch:) forControlEvents:UIControlEventValueChanged];
[cell addSubview:self.privateBrowsingSwitch];
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
Every time cellForRowAtIndexPath is called you have to replace the specific data that needs to be displayed for a cell at that position. This includes things like labels, images and your UISwitch.
This occurs because UITableViews use a small number of cells that are reused.
In cellForRowAtIndexPath add something like this:
switchView.on = [self isSwitchOnForCellAtIndexPath:indexPath]
Then write whatever logic is required to determine if the switch should be on or not.
I am trying to change the color of a button when pressed that is in a tableviewCell. However my code changes the color of every button in the table and not just the one in the cell I selected,
How would I go about just changing the color of the button I pressed.
Please see my code below,
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UIButton *addNotesButton = (UIButton *)[cell viewWithTag:106];
[addNotesButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Test";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UIButton *addNotesButton = (UIButton *)[cell viewWithTag:106];/
[addNotesButton addTarget:self action:#selector(addNotes :) forControlEvents:UIControlEventTouchUpInside];
}
The main issue might be in your cellForRowAtIndexPath: method. UITableView cells are re-used as they are displayed on the screen. dequeueReusableCellWithIdentifier: method returns a cell if it has been marked as ready for reuse. You must have seen this method of UITableView being used in cellForRowAtIndexPath: method. (See this link)
So in cellForRowAtIndexPath: you will have to configure each cell as it is being loaded or else it will display old values (since the cells are being reused).
You can either declare a property or a simple variable of type NSIndexPath.Let the variable be called _selectedIndexPath. Then in didSelectRowAtIndexPath: you can assign this property to the indexPath selected.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSArray *indexPaths = nil;
if (_selectedIndexPath) {
indexPaths = #[_selectedIndexPath, indexPath];
} else {
indexPaths = #[indexPath];
}
_selectedIndexPath = indexPath;
[tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
}
- (void)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Your Cell Identifier"];
UIButton *addNotesButton = (UIButton *)[cell viewWithTag:106];
if (indexPath.row == _selectedIndexPath.row) {
[addNotesButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
} else {
[addNotesButton setTitleColor:[UIColor clearColor] forState:UIControlStateNormal];
}
}
You don't need to change color manually in did select row at index path. Just set the color for UIControlStateSelected and on the action of button tap set the buttons selected property to YES. From your code i think this should work.
inside cell for row at index path method
[addNotesButton setTitleColor:[UIColor blueColor] forState:UIControlStateSelected];
and in button action method
-(IBAction)addNotes:(id)sender
{
UIButton *button = (UIButton*)sender;
buttons.selected = !button.isSelected;
}
I think this will work.
After trying everything and failed. I ended up having a hidden value in each row that would change when the button is pressed. So the code reads the value then configures the button for each row.
I have a question about UITAbleViewCell's.
I have implemented UITableViewDelegate method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
cell.backgroundColor = [UIColor redColor];
cell.textLabel.textColor = [UIColor redColor];
cell.textLabel.text = #"Title";
}
After I click on desired cell, nothing happens...
Why it doesn't work as I expected? Also, what should I do to make it work?
You have to create some base model for cell states e.g:
#property NSString *modelState = #"red"; // this is fast hint, but it can be a enum with states.
all cell will have one title after tap.
... other controller code...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self.restaurantTable dequeueReusableCellWithIdentifier:#"cell_ID"];
// cell customization method
[self customizeCell:cell accordingToStateStr:modelState];
return cell;
}
... other controller code...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
// Set other state for cell
self.modelState = #"red";
[tableView reloadData];
}
- (void)customizeCell:(UITableViewCell*)cell accordingToStateStr:(NSString *)str {
if ([str isEqualToString:#"red"]) {
cell.backgroundColor = [UIColor redColor];
cell.textLabel.textColor = [UIColor redColor];
cell.textLabel.text = #"Title";
} else if(...) {
//Other options..
}
}
[tableView reloadData]; - will trigger once again "cellForRow" method and your table will be redrawn according to new model.
You can use for cell states emuns instead NSString object (this is only scaffold for you).
Try this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
// config the selected cell
....
}
You should ask the UITableView for the cell directly rather than ask its delegate (self in your code). Cause its delegate may dequeue or create a fresh cell rather than giving you the cell seleceted.
I'm trying to change states of the label in my table view cell.
I want to keep a cell selected while I push a different view controller and move back to the view controller with my tableview.
When I select another row I want to remove highlight of previously selected row's lable (deselect the previously selected row) and Highlight the current row's label.
Is - (void)deselectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated supposed to call - (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated with highlighted 'NO' for that Cell ?
Note: I'm not UITableViewController.
Keep cell selected:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.selected = YES;
//Other code
}
Ensure that the class cell don't have selected = NONE in interface builder.
Unselect last row:
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *currentSelectedIndexPath = [tableView indexPathForSelectedRow];
if (currentSelectedIndexPath)
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.selected = NO;
}
return indexPath;
}
First, you should set TableviewCell properly [cell setSelectionStyle:UITableViewCellSelectionStyleGray]; in method :
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Other then this, you can set custom background of selected cell by
UIView *bgColorView = [[UIView alloc] init];
bgColorView.backgroundColor = [UIColor colorWithWhite:0.97 alpha:1.0];
bgColorView.layer.masksToBounds = YES;
[cell setSelectedBackgroundView:bgColorView];
For Your highlight selected cell problem, you can use Simple flag like
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSIndexPath *ip= [NSIndexPath indexPathForRow:flagForLastSelectedRow inSection:0];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
flagForLastSelectedRow=indexPath.row;
}