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
{
}
Related
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;
}
I have a custoum cell with an image , and i want to change the image only when cell is selected.
This i was trying :
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (!tableView.tag==0) {
TableViewCell2 *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (!cell) {
cell=[[TableViewCell2 alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"cell"];
}
// cell.cam.image = [UIImage imageNamed:#"cam_normal.png"];
cell.cam.highlightedImage = [UIImage imageNamed:#"cam_selected.png"];
}
}
but the image is not changing.
This is working for a normal cell.
Another try was this in cellForRowAtIndexPath
if (cell.selected==TRUE) {
cell.cam.image=[UIImage imageNamed:#"cam_selected.png"];
}
You already get the cell as a parameter but fetch another one when using dequeueReusableCellWithIdentifier!
Try something like this:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!tableView.tag==0)
{
TableViewCell2 *changeImageCell = (TableViewCell2*) cell;
changeImageCell.cam.highlightedImage = [UIImage imageNamed:#"cam_selected.png"];
}
}
You have to do 2 things:
1. Change the image immediately when the cell is selected.
To do this you must first implement UITableViewCell delegate. But since you already have tableViewWillDisplayCel:forRowAtIndexPath:, I assume that you already have the delegate implemented.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
TableViewCell2 *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.cam.highlightedImage = [UIImage imageNamed:#"cam_selected"];
}
You could change the image back when the user deselect the cell.
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
TableViewCell2 *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.cam.highlightedImage = [UIImage imageNamed:#"cam_unselected"];
}
2. Persist the selection when the cell is reused.
Again, when the cell is reused, you have to check whether it is selected or not. Then assign the image accordingly.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TableViewCell2 *cell = [tableView dequeReusableCellWithIdentifier:#"cell"];
BOOL isRowSelected = [indexPath isEqaul:[tableView indexPathForSelectedRow]];
if (isRowSelected) {
cell.cam.highlightedImage = [UIImage imageNamed:#"cam_selected"];
} else {
cell.cam.hightlightedImage = [UIImage imageNamed:#"cam_unselected"];
}
}
Two things I notice here. First you never use true or TRUE in Objective-C. You use BOOL with YES and NO. Second, you rarely need to use dequeReusableCellWithIdentifier: outside tableView:cellForRowAtIndexPath:. Why did you do it there?
I know there are lot of answers to this question . But it didn't achieved the desired result . didDEselectrow is not working . I have a UIImageView which i have set to hidden True in cellforRowAtIndex. And when someone selects any row value for hidden is set to false .
**My main problem is when i select another row , the previous row status does not change and it also shows selected . I have attached the necessary snippet of my code ,Please check and help me through this . **
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
EventTypeTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"Event_Type" forIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if (cell.selectionStatus)
[cell.selectEvent setHidden:NO];
else
[cell.selectEvent setHidden:YES];
[cell.eventTypeName setText:[eventTypeName objectAtIndex:indexPath.row]];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
EventTypeTableViewCell *cell = (EventTypeTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
if(cell.selectionStatus == TRUE)
{
cell.selectionStatus = FALSE;
}
else
{
] cell.selectionStatus = TRUE;
}
[tableView reloadData];
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
EventTypeTableViewCell *cell = (EventTypeTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
if(cell.selectionStatus == FALSE)
{
//Do your stuff
cell.selectionStatus = TRUE;
}
else
{
//Do your stuff
cell.selectionStatus = FALSE;
}
[tableView reloadData];
}
I suspect that didDeselect is not being called because you are allowing multiple selections in your tableView.
Have you set your table view's selection style to "single selection"? You can either do it in interface builder/storyboard or you can do it programmatically:
- (void) viewDidLoad {
self.tableView.allowsMultipleSelection = NO;
}
That way when you select another row it will deselect the old selection. Also you can simplify your code and make everything look better by not calling [tableView reloadData] every time one cell's selected state changes. The way I would suggest doing that is to change the hidden state of selectEvent within EventTypeTableViewCell whenever the cell's selection changes.
That leaves you with this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
EventTypeTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"Event_Type" forIndexPath:indexPath];
[cell.eventTypeName setText:[eventTypeName objectAtIndex:indexPath.row]];
return cell;
}
And some method overrides within your definition of EventTypeTableViewCell:
#implementation EventTypeTableViewCell
/// Your code ///
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
self.selectEvent.hidden = !selected;
}
#end
Try this ::
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}
In a VC I have 2 tableViews - 1 main and other is added in a drop down menu. From drop down menu TableView "ddTableView", I have added 5 cells in Storyboard itself as prototype cells. Each cell contains an image and a Label. Have also set identifier for each cell. Have also set Accessory Type as "Disclosure Indicator" for each cell of ddTableView.
DataSource and Delegate for mainTV is set to the VC and delegate for ddTableView is set the VC. As the rows are added within the storyboard, I didn't set any datasource for ddTableView in my VC. I managed my delegate methods like this :-
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == ddTableView) {
// RETURNS NIL ???
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSLog(#"CELL Identifier = %#", cell.reuseIdentifier);
return cell;
} else {
}
}
-(void )tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == ddTableView) {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSLog (#" CELL Clicked of - %#", cell.reuseIdentifier);
}
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == ddTableView)
return 44;
else
return 60;
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == ddTableView)
return 5;
else
return [chatMsgsArr count];
}
It does call respective delegate method. For cellForRowAtIndexPath it returns cell as nil. Why so ? And on execution, I don't see any contents of the table view - table is blank. I changed the bg color of image and text color also, but yet nothing is seen on execution.
Why so ? Where I may be going wrong ?
You have to allocate the cell, the first time cellForRowAtIndexPath is called. If the cell is not allocated it would return nil as you are getting right now.
What you need to do is allocate the cell only once, the first time you enter cellForRowAtIndexPath. After that you can reuse it as you have done.
If you are planning to use the default tableViewCell your method should look as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = #"your_cell_identifier_name";
if (cell == nil)
{
UITableViewCell *cell = [UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
else
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
}
//write the code to populate your cell with data here
//return the cell object
return cell;
}
Hope this helps! :)
- (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] ;
}
if (tableView == ddTableView) {
NSLog(#"CELL Identifier = %d", indexpath.row);
} else {
NSLog(#"CELL Identifier = %#", [chatMsgsArr objectAtIndex:indexPath.row]);
}
return cell;
}
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;
}