I am developing an iOS application. I have used a table view. When the user clicks to any cell then the cell expands. But some cells are not expanding in iOS 7. Other versions run correctly. Below is the sample code. How can I correct it?
- (BOOL)cellIsSelected:(NSIndexPath *)indexPath {
// Return whether the cell at the specified index path is selected or not
NSNumber *selectedIndex = [selectedIndexes objectForKey:indexPath];
return selectedIndex == nil ? FALSE : [selectedIndex boolValue];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if([self cellIsSelected:indexPath])
{
return 111;
}
// Cell isn't selected so return single height
return 41;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.filteredItineraries count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"FlightTracker";
CellFlightTracker *cell = (CellFlightTracker *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if(cell == nil)
{
NSArray *nib=nil;
nib = [[NSBundle mainBundle] loadNibNamed:#"CellFlightTracker" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
if([self cellIsSelected:indexPath])
{
cell.backgroundColor=[UIColor blackColor];
}else
{
cell.backgroundColor=[UIColor darkGrayColor];
}
return cell;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if([self cellIsSelected:indexPath])
cell.backgroundColor= [UIColor blackColor];
else
cell.backgroundColor= [UIColor darkGrayColor];
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:TRUE];
// Toggle 'selected' state
BOOL isSelected = ![self cellIsSelected:indexPath];
// Store cell 'selected' state keyed on indexPath
NSNumber *selectedIndex = [NSNumber numberWithBool:isSelected];
[selectedIndexes setObject:selectedIndex forKey:indexPath];
// This is where magic happens...
[tableView1 beginUpdates];
CellFlightTracker *selectedCell = (CellFlightTracker*)[tableView cellForRowAtIndexPath:indexPath];
if(selectedCell.lblDepartureAirportStatus.hidden)
[selectedCell.lblDepartureAirportStatus setHidden:NO];
else
[selectedCell.lblDepartureAirportStatus setHidden:YES];
[tableView1 endUpdates];
}
It would be better if you subclass and UITableViewCell and use the layoutSubviews to adjust when you adjust the size of the cell.
//In SMTableViewCell.h
#interface SMTableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *statusLabel;
#property (weak, nonatomic) IBOutlet UIButton *seeMoreButton;
//SMTableViewCell.m
- (void)layoutSubviews
{
CGRect labelFrame = self.statusLabel.frame;
labelFrame.size.height = self.frame.size.height - 55.0f;
self.statusLabel.frame = labelFrame;
CGRect buttonFrame = self.seeMoreButton.frame;
buttonFrame.origin.y = labelFrame.origin.y+labelFrame.size.height+10.0f;
self.seeMoreButton.frame = buttonFrame;
}
Keep an array to store the selectedIndexPaths
#property (nonatomic, strong) NSMutableArray *selectedIndexPaths;
Calculate the height of the cell
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
BOOL isSelected = [self.selectedIndexPaths containsObject:indexPath];
CGFloat maxHeight = MAXFLOAT;
CGFloat minHeight = 40.0f;
CGFloat constrainHeight = isSelected?maxHeight:minHeight;
CGFloat constrainWidth = tableView.frame.size.width - 20.0f;
NSString *text = self.items[indexPath.row];
CGSize constrainSize = CGSizeMake(constrainWidth, constrainHeight);
CGSize labelSize = [text sizeWithFont:[UIFont systemFontOfSize:15.0f]
constrainedToSize:constrainSize
lineBreakMode:NSLineBreakByCharWrapping];
return MAX(labelSize.height+75, 100.0f);
}
Initialize custom Show more TableViewCell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"CellIdentifier";
SMTableViewCell *cell= (SMTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[[NSBundle mainBundle]loadNibNamed:NSStringFromClass([SMTableViewCell class])
owner:nil
options:nil] lastObject];
}
BOOL isSelected = [self.selectedIndexPaths containsObject:indexPath];
cell.statusLabel.numberOfLines = isSelected?0:2;
NSString *text = self.items[indexPath.row];
cell.statusLabel.text = text;
NSString *buttonTitle = isSelected?#"See Less":#"See More";
[cell.seeMoreButton setTitle:buttonTitle forState:UIControlStateNormal];
[cell.seeMoreButton addTarget:self action:#selector(seeMoreButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[cell.seeMoreButton setTag:indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
Button click event method
- (void)seeMoreButtonPressed:(UIButton *)button
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:button.tag inSection:0];
[self addOrRemoveSelectedIndexPath:indexPath];
}
- (void)addOrRemoveSelectedIndexPath:(NSIndexPath *)indexPath
{
if (!self.selectedIndexPaths) {
self.selectedIndexPaths = [NSMutableArray new];
}
BOOL containsIndexPath = [self.selectedIndexPaths containsObject:indexPath];
if (containsIndexPath) {
[self.selectedIndexPaths removeObject:indexPath];
}else{
[self.selectedIndexPaths addObject:indexPath];
}
[self.tableView reloadRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
}
Same Event is given if the cell is selected
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[self addOrRemoveSelectedIndexPath:indexPath];
}
Sample Demo project link.
Related
I am loading a UIWebview in a expand/collapse UITableView. I need to change the row height according to the UIWebview content height. if i set the UIWebview delegate in the UITableview, the UIWebview delgate method keeps get calling over and over. i am calling the webviewDidFinishLoad method to get the content height. Any kind of help/suggestion would be very appreciative.
- (BOOL)tableView:(UITableView *)tableView canCollapseSection:(NSInteger)section
{
return YES;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.restauRantMenuArray.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([self tableView:self.restaurantMenuTableView canCollapseSection:section])
{
if ([expandedSections containsIndex:section])
{
return 2; // 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
{
if ([self tableView:self.restaurantMenuTableView canCollapseSection:indexPath.section])
{
if (indexPath.row == 0)
{
static NSString *MyIdentifier = #"menuTitleCell";
RestaurantMenuTitleTableViewCell *cell =(RestaurantMenuTitleTableViewCell*) [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[RestaurantMenuTitleTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"RestaurantMenuTitleTableViewCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
RestaurantMenuItemObject *object = [self.restauRantMenuArray objectAtIndex:indexPath.section];
cell.titleWebView.opaque = NO;
cell.titleWebView.backgroundColor = [UIColor clearColor];
[cell.titleWebView loadHTMLString:object.menuTitle baseURL:nil];
cell.titleWebView.scrollView.scrollEnabled = NO;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.backgroundColor = [UIColor whiteColor];
return cell;
}
else
{
static NSString *MyIdentifier = #"menuContentCell";
RestaurantMenuContentTableViewCell *cell =(RestaurantMenuContentTableViewCell*) [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[RestaurantMenuContentTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"RestaurantMenuContentTableViewCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
RestaurantMenuItemObject *object = [self.restauRantMenuArray objectAtIndex:indexPath.section];
cell.contentWebView.tag = indexPath.section + 1000;
cell.contentWebView.opaque = NO;
cell.contentWebView.backgroundColor = [UIColor clearColor];
[cell.contentWebView loadHTMLString:object.menuContent baseURL:nil];
//cell.contentWebView.scrollView.delegate = self;
[cell.contentWebView.scrollView setShowsHorizontalScrollIndicator:NO];
// cell.contentWebView.scrollView.scrollEnabled = NO;
//cell.contentWebView.delegate = self;
if([[self.imageHeightArray objectAtIndex:indexPath.section] isEqualToString:#"150"])
{
//cell.contentWebView.delegate = self;
}
// first row
//cell.textLabel.text = #"Expandable"; // only top row showing
if ([expandedSections containsIndex:indexPath.section])
{
//cell.accessoryView = [DTCustomColoredAccessory accessoryWithColor:[UIColor grayColor] type:DTCustomColoredAccessoryTypeUp];
}
else
{
//cell.accessoryView = [DTCustomColoredAccessory accessoryWithColor:[UIColor grayColor] type:DTCustomColoredAccessoryTypeDown]
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.backgroundColor = [UIColor clearColor];
return cell;
}
}
else
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.backgroundColor = [UIColor clearColor];
return cell;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
RestaurantMenuItemObject *object = [self.restauRantMenuArray objectAtIndex:indexPath.section];
UIWebView *thisWebView = (UIWebView*)[self.restaurantMenuTableView viewWithTag:indexPath.section+1000];
[thisWebView loadHTMLString:object.menuContent baseURL:nil];
thisWebView.delegate = self;
//[tableView deselectRowAtIndexPath:indexPath animated:YES];
//if there is any previous selected index
//if selected index is not the previous selected
if (selectedIndex && (selectedIndex.section != indexPath.section)) {
[self collapseOrExpandForIndexPath:selectedIndex inTableView:tableView];
}
if ([selectedIndex isEqual:indexPath]) {
selectedIndex = nil;
}
else{
selectedIndex = [NSIndexPath indexPathForRow:0 inSection:indexPath.section];
}
if ([self tableView:tableView canCollapseSection:indexPath.section])
{
[self collapseOrExpandForIndexPath:indexPath inTableView:tableView];
if (indexPath.row == 0) {
[tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
}
}
- (void)collapseOrExpandForIndexPath:(NSIndexPath *)indexPath inTableView:(UITableView *)tableView{
if (!indexPath.row)
{
// 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];
}
if (currentlyExpanded)
{
[tableView deleteRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationTop];
}
else
{
//RestaurantMenuItemObject *object = [self.restauRantMenuArray objectAtIndex:indexPath.section];
// UIWebView *thisWebView = (UIWebView*)[self.restaurantMenuTableView viewWithTag:indexPath.section+1000];
//
// [thisWebView loadHTMLString:object.menuContent baseURL:nil];
//
// thisWebView.delegate = self;
[tableView insertRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationTop];
}
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
//return UITableViewAutomaticDimension;
if(indexPath.row == 0)
return 50.00;
else
{
return 240;//[[self.imageHeightArray objectAtIndex:indexPath.section] integerValue];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 1.00;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 1.00;
}
pragma mark Table View Delegate Method ends
Create a class level property (CGFloat),say webViewHeight to track web view's height.
On table view didSelectRowAtIndexPath method load url in web view.
Calculate web view height in webviewDidFinishLoad delegate method of web view and set it in class level height variable,webViewHeight. After calculating height call [tableView reloadData];
Set selected cell height with webViewHeight and rest with default,say 44.0 in heightForRowAtIndexPath method of data source.
IMP: Set maximum web view height also if calculated height exceed max height set calculated height to max height. And enable web view scrolling so that user is able to view all web view content.
I have a table view and 2 custom cells inside it. I want to use a (X) symbol i.e. the cross symbol and the tick symbol. I know for tick we have UITableViewCellAccessoryCheckmark but what to do for the (X) symbol. Can we have any custom accessory for this or else how to achieve this?
My code:
#pragma mark - Table View Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 2;
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
optionsLabelArray = [[NSArray alloc] initWithObjects:#"Yes", #"No", nil];
static NSString *CellIdentifier = #"CheckerCell";
CustomCell *cell =[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.optionLabel.text = [optionsLabelArray objectAtIndex:indexPath.row];
cell.optionLabelSubtitle.text = [optionsLabelSubtitleArray objectAtIndex:indexPath.row];
if(indexPath.row == 0)
{
cell.textLabel.textColor = [UIColor colorWithRed:78/255.0 green:157/255.0 blue:19/255.0 alpha:1.0];
}
else if(indexPath.row == 1)
{
cell.textLabel.textColor = [UIColor colorWithRed:167/255.0 green:19/255.0 blue:43/255.0 alpha:1.0];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView ==_optionsTableView1) {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
previousSelectedCell1.accessoryType = UITableViewCellAccessoryNone;
cell.accessoryType=UITableViewCellAccessoryCheckmark;
previousSelectedCell1 = cell;
NSLog(#"Row : %ld", (long)indexPath.row);
if(indexPath.row == 0)
{
self.weatherSafeToPlay = YES;
}
else
{
// MatchDayDataController *sharedController = [MatchDayDataController sharedDataController];
// sharedController.actions = [sharedController.actions stringByAppendingString:#"Check Weather. "];
//[sharedController.actions appendString:#"Check Weather. "];
self.weatherSafeToPlay = NO;
}
NSLog(#"Is Weather safe: %hhd", self.weatherSafeToPlay);
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
not heard of any accessory type for cross but in such cases, i simply use unicode characters.
It's lighter than using an image and is a simple matter of just changing the text.
#"\u2713" for ✓
#"\u2717" for ✗
You can:
Create a custom UITableViewCell having a 32by32 (or any dimension) UILabel (on the right/left/middle/wherever)
in -didSelectRowAtIndexPath, you can change the text of this UILabel
#"\u2713" for checkmark or #"\u2717" for crossmark
A simple example (on the default UITableViewCell's default textLabel, just for the idea):
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if([cell.textLabel.text isEqualToString:#"\u2713"]) {
cell.textLabel.text = #"\u2717";
}
else {
cell.textLabel.text = #"\u2713";
}
}
OR... when not using a custom cell, something like:
-(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];
}
//set your text to cell.textLabel.text
//create your own UILabel
UILabel *lblAcc = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 32, 32)];
[lblAcc setTag:100];
[lblAcc setText:#"?"];
[lblAcc setBackgroundColor:[UIColor redColor]];
[lblAcc setTextAlignment:NSTextAlignmentCenter];
//set as custom AccessoryView on cell
[cell setAccessoryView:lblAcc];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *strAccessory = [(UILabel *) [cell viewWithTag:100] text];
//the -isEqualToString is a bit heavier than checking a simple bool or int value
//so since you should be remembering the selected cells anyways, you can change
//the if-logic to compare with a bool rather than the string comparison.
//but for now, we'll do:
if([strAccessory isEqualToString:#"\u2713"]) {
[(UILabel *) [cell viewWithTag:100] setText:#"\u2717"];
}
else {
[(UILabel *) [cell viewWithTag:100] setText:#"\u2713"];
}
}
for more unicode characters... this link:
http://en.wikibooks.org/wiki/Unicode/List_of_useful_symbols
You can assign your own image to accessoryView of table cell. Create an image of (X) symbol and use that image as accessoryView.
cell.accessoryView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"Your X Image"]];
In my tableview each cell gets a subview by didselectRowAtIndexPath to highlight the current selected row. Everything works fine but in the moment when the tableview was scrolled the subview won't hide from a cell which was selected before.
In short: How do you would make a replacement for "Managing Cell Selection and Highlighting"?
Thanks in advance!
Here is my code:
#import "ViewController.h"
#interface ViewController () <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic,strong) NSArray *tableData;
#end
#implementation ViewController
#synthesize checked_icon;
- (void)viewDidLoad {
[super viewDidLoad];
self.tableData = #[#"A",#"B",#"C",#"D",#"E",#"F",#"G",#"H",#"I",#"J",#"K",#"L",#"M",#"N",#"O",#"P",#"Q",#"R",#"S",#"T"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.tableData count];
}
- (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];
checked_icon = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 44)];
checked_icon.backgroundColor =[UIColor redColor];
}
cell.textLabel.text = self.tableData[indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSIndexPath *currentSelectedIndexPath = [tableView indexPathForSelectedRow];
if (currentSelectedIndexPath != nil)
{
[[tableView cellForRowAtIndexPath:currentSelectedIndexPath] setBackgroundColor: [UIColor whiteColor]];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:currentSelectedIndexPath];
if (cell.isSelected == YES) {
checked_icon.backgroundColor = [UIColor redColor];
}
else {
checked_icon.backgroundColor = [UIColor clearColor];
}
}
return indexPath;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[[tableView cellForRowAtIndexPath:indexPath] setBackgroundColor:[UIColor lightGrayColor]];
UITableViewCell *selectedcell = [tableView cellForRowAtIndexPath:indexPath];
[selectedcell.contentView addSubview:checked_icon];
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (cell.isSelected == YES) {
[cell setBackgroundColor:[UIColor lightGrayColor]];
}
else {
[cell setBackgroundColor:[UIColor whiteColor]];
}
}
#end
You should use 'selectedBackgroundView' property of UITableViewCell, as selection will be handled for you.
EDIT
The proper way to do this would be to create a subclass of UITableViewCell and have a reference to your checkmark in there.
While the code from my original post will work, it's not the best way to do it and will quickly get complicated if your cell view gets more complex.
ORIGINAL
If you don't want to use 'selectedBackgroundView', then this should probably solve your problem:
- (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];
UIView *checked_icon = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 44)];
checked_icon.tag = 1234;
[cell.contentView addSubview:checked_icon];
}
UIView *checked_icon = [cell.contentView viewWithTag:1234];
// Note: color should be set each time a cell is presented
if (cell.isSelected) {
checked_icon.backgroundColor = [UIColor redColor];
}
else {
checked_icon.backgroundColor = [UIColor clearColor];
}
cell.textLabel.text = self.tableData[indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
Thanks to MrNickBarker!
viewWithTag seems to be the one and only solution...
Here is the code: (not perfect but it works)
#import "ViewController.h"
#interface ViewController () <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic,strong) NSArray *tableData;
#end
#implementation ViewController
#synthesize checked_icon;
- (void)viewDidLoad {
[super viewDidLoad];
self.tableData = #[#"A",#"B",#"C",#"D",#"E",#"F",#"G",#"H",#"I",#"J",#"K",#"L",#"M",#"N",#"O",#"P",#"Q",#"R",#"S",#"T"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = [NSString stringWithFormat:#"cell-%d",indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
checked_icon = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 44)];
checked_icon.tag = 1234;
[cell.contentView addSubview:checked_icon];
}
cell.textLabel.text = self.tableData[indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSIndexPath *currentSelectedIndexPath = [tableView indexPathForSelectedRow];
if (currentSelectedIndexPath != nil) {
[[tableView cellForRowAtIndexPath:currentSelectedIndexPath] setBackgroundColor: [UIColor whiteColor]];
UITableViewCell *selectedcell = [tableView cellForRowAtIndexPath:currentSelectedIndexPath];
checked_icon = [selectedcell.contentView viewWithTag:1234];
if (selectedcell.isSelected == YES) {
checked_icon.backgroundColor = [UIColor redColor];
}
else {
checked_icon.backgroundColor = [UIColor clearColor];
}
}
checked_icon.backgroundColor = [UIColor clearColor];
return indexPath;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[[tableView cellForRowAtIndexPath:indexPath] setBackgroundColor:[UIColor lightGrayColor]];
UITableViewCell *selectedcell = [tableView cellForRowAtIndexPath:indexPath];
checked_icon = [selectedcell.contentView viewWithTag:1234];
if (selectedcell.isSelected == YES) {
NSLog(#"redColor");
checked_icon.backgroundColor = [UIColor clearColor];
}
else {
NSLog(#"clearColor");
checked_icon.backgroundColor = [UIColor clearColor];
}
checked_icon.backgroundColor = [UIColor redColor];
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
checked_icon = [cell.contentView viewWithTag:1234];
if (cell.isSelected == YES) {
[cell setBackgroundColor:[UIColor lightGrayColor]];
checked_icon.backgroundColor = [UIColor redColor];
}
else {
[cell setBackgroundColor:[UIColor whiteColor]];
checked_icon.backgroundColor = [UIColor clearColor];
}
}
#end
I have subclass of UITableViewCell. Here is my setup
I have used Autolayout. Now when user swipe on cell , I can see "Delete" button , but it overlaps my right side imageview. Cell contents are not shifting. Here is my code
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.recentItemsArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"ProductCell";
ProductCell *cell = (ProductCell*)[tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil)
{
NSArray *cellArray = [[NSBundle mainBundle] loadNibNamed:#"ProductCell" owner:self options:nil];
cell=[cellArray objectAtIndex:0];
tableView.separatorColor = [UIColor clearColor];
}
Product *product = [self.recentItemsArray objectAtIndex:indexPath.row];
cell.lblProductName.text = product.name;
cell.lblNoOfBids.text = [NSString stringWithFormat:#"%#",product.numberOfBids];
cell.lblBuyItNowPrice.text = [NSString stringWithFormat:#"%# %#",CURRENCY_TYPE,product.buyItNowPrice];
cell.lblTimeRemaining.text = product.timeRemaining;
cell.lblLatestBid.text = [NSString stringWithFormat:#"%# %#",CURRENCY_TYPE,product.currentBidPrice];
cell.lblUserName.text = product.sellerName;
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 110.0f;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
//add code here for when you hit delete
[CommonUtils showAlertWithTitle:#"Alert" andMessage:#"Do you want to delete this product?"];
}
}
I saw several question on Stackoverflow , but didn't get any solution.
Can any body tell me what I am doing wrong ? Any kind of help is highly appreciated. Thanks
Update::
I tried adding UIImageView programatically. still image views are not shifting
- (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];
UIImageView* imageView = [[UIImageView alloc]initWithFrame:CGRectMake(260, 0, 50, 60)];
imageView.backgroundColor = [UIColor yellowColor];
[cell.contentView addSubview:imageView];
UIImageView* imageView1 = [[UIImageView alloc]initWithFrame:CGRectMake(20.0, 0, 60, 60)];
imageView1.backgroundColor = [UIColor redColor];
[cell.contentView addSubview:imageView1];
}
//cell.textLabel.text = #"ABC";
// Configure the cell...
return cell;
}
It happend with me. Verify if some cell property have the same name from other property in the view where the UITableView is.
I want to expand the cell size after clicking a seeMoreBtn on cell.
The label and cells have varying length, but their is a constraint in size of label.
When a status is too big, I added a seeMoreBtn, after clicking on see more the remaining text will be shown below, then how to increase the label and cell size.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
NSString *text = [items objectAtIndex:[indexPath row]];
CGSize constraint = CGSizeMake(300.0f, 150.0f);
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:constraint lineBreakMode:NSLineBreakByCharWrapping];
CGFloat height1 = MAX(size.height, 44.0f);
return height1 + (40.0f);
}
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"Cell-%d",indexPath.row];
cell=[tv dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
int lbltag = 1000;
label=[[UILabel alloc]initWithFrame:CGRectZero];
[label setLineBreakMode:NSLineBreakByWordWrapping];
[label setMinimumScaleFactor:14.0f];
[label setNumberOfLines:0];
[label setFont:[UIFont systemFontOfSize:14.0f]];
NSString *text = [items objectAtIndex:[indexPath row]];
[label setText:text];
label.tag = lbltag;
[cell addSubview:label];
CGSize constraint1=CGSizeMake(300.0f, 150.0f);
CGSize size1=[text sizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:constraint1 lineBreakMode:NSLineBreakByWordWrapping];
[label setFrame:CGRectMake(10.0f, 10.0f, 300.0f, MAX(size1.height, 44.0f))];
int countText=text.length;
if (countText>=350) {
seeMoreBtn=[UIButton buttonWithType:UIButtonTypeRoundedRect];
[seeMoreBtn setTitle:#"See More" forState:UIControlStateNormal];
seeMoreBtn.frame=CGRectMake(220.0f, MAX(size1.height, 44.0f)-10, 80.0f, 20.0f);
seeMoreBtn.tag=indexPath.row ;
[seeMoreBtn addTarget:self action:#selector(increaseSize:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:seeMoreBtn];
}
return cell;
}
-(void)increaseSize:(UIButton *)sender{
//What to write here that can adjust the label and cell size
}
It would be better, if you subclass the UITableViewCell and use the layoutSubviews to adjust when you adjust the size of the cell.
//In SMTableViewCell.h
#interface SMTableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *statusLabel;
#property (weak, nonatomic) IBOutlet UIButton *seeMoreButton;
//SMTableViewCell.m
- (void)layoutSubviews
{
CGRect labelFrame = self.statusLabel.frame;
labelFrame.size.height = self.frame.size.height - 55.0f;
self.statusLabel.frame = labelFrame;
CGRect buttonFrame = self.seeMoreButton.frame;
buttonFrame.origin.y = labelFrame.origin.y+labelFrame.size.height+10.0f;
self.seeMoreButton.frame = buttonFrame;
}
Keep an array to store the selectedIndexPaths:
#property (nonatomic, strong) NSMutableArray *selectedIndexPaths;
Calculate the height of the cell:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
BOOL isSelected = [self.selectedIndexPaths containsObject:indexPath];
CGFloat maxHeight = MAXFLOAT;
CGFloat minHeight = 40.0f;
CGFloat constrainHeight = isSelected?maxHeight:minHeight;
CGFloat constrainWidth = tableView.frame.size.width - 20.0f;
NSString *text = self.items[indexPath.row];
CGSize constrainSize = CGSizeMake(constrainWidth, constrainHeight);
CGSize labelSize = [text sizeWithFont:[UIFont systemFontOfSize:15.0f]
constrainedToSize:constrainSize
lineBreakMode:NSLineBreakByCharWrapping];
return MAX(labelSize.height+75, 100.0f);
}
Initialize custom Show more TableViewCell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"CellIdentifier";
SMTableViewCell *cell= (SMTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[[NSBundle mainBundle]loadNibNamed:NSStringFromClass([SMTableViewCell class])
owner:nil
options:nil] lastObject];
}
BOOL isSelected = [self.selectedIndexPaths containsObject:indexPath];
cell.statusLabel.numberOfLines = isSelected?0:2;
NSString *text = self.items[indexPath.row];
cell.statusLabel.text = text;
NSString *buttonTitle = isSelected?#"See Less":#"See More";
[cell.seeMoreButton setTitle:buttonTitle forState:UIControlStateNormal];
[cell.seeMoreButton addTarget:self action:#selector(seeMoreButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[cell.seeMoreButton setTag:indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
Button click event method:
- (void)seeMoreButtonPressed:(UIButton *)button
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:button.tag inSection:0];
[self addOrRemoveSelectedIndexPath:indexPath];
}
- (void)addOrRemoveSelectedIndexPath:(NSIndexPath *)indexPath
{
if (!self.selectedIndexPaths) {
self.selectedIndexPaths = [NSMutableArray new];
}
BOOL containsIndexPath = [self.selectedIndexPaths containsObject:indexPath];
if (containsIndexPath) {
[self.selectedIndexPaths removeObject:indexPath];
}else{
[self.selectedIndexPaths addObject:indexPath];
}
[self.tableView reloadRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
}
Same Event is given if the cell is selected:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[self addOrRemoveSelectedIndexPath:indexPath];
}
Sample Demo project link.
Add a property like:
#property(strong, nonatomic) NSArray *enlargedIndexPaths;
Initialize it to an empty array. Implement the table view delegate:
- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return ([self.enlargedIndexPaths containsObject:indexPath])? 88.0 : 44.0;
}
Then in increaseSize:
UITableViewCell *cell = sender.superview;
NSIndexPath *indexPath = [self.tableView indexPathFoCell:cell];
[self.enlargedIndexPaths addObject:indexPath];
// do you want to enlarge more than one at a time? You can remove index paths
// here, too. Just reload them below
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:self.enlargedIndexPaths] withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
Well, the idea is to change the cells height, based on a value you set for the cell.
You can have an NSArray, where you just mark for all cells a value: isExpanded (true or false).
To recap, create an NSMutableArray that will store the cell state (expanded or not):
NSMutableArray *cellState;
init the array and fill it with zeros for all your UITableView items Array.
When the cell is expanded, set the cellState objectAtIndex value from 0 to 1 (marking it as expanded).
Then reload that cell:
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section]] withRowAnimation:UITableViewRowAnimationFade];
and modify the - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; function to return a bigger value if the cell is expanded...
That's it!