I have a UITableView with a custom cell and at the beginning all is empty.
My UITableViewCell has a UITextView and when i tap on the screen i create a new cell and fire on it:
#import "MemoViewController.h"
#import "MemoViewCell.h"
#import "MemoModel.h"
static NSString *CellIdentifier = #"MemoCell";
#interface MemoViewController () <UITextViewDelegate>
#property (nonatomic, strong) MemoModel *model;
#property (nonatomic, strong) NSMutableDictionary *offscreenCells;
#end
#implementation MemoViewController
{
NSIndexPath *currentIndexPath;
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
self.model = [[MemoModel alloc] init];
//[self.model populateDataSource];
self.offscreenCells = [NSMutableDictionary dictionary];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerClass:[MemoViewCell class] forCellReuseIdentifier:CellIdentifier];
self.tableView.rowHeight = UITableViewAutomaticDimension;
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(insertNewRow:)];
gestureRecognizer.cancelsTouchesInView = NO;
[self.tableView addGestureRecognizer:gestureRecognizer];
currentIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
UIBarButtonItem *editButton = [[UIBarButtonItem alloc]
initWithTitle:#"Modifica"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(editButtonPressed:)];
self.navigationItem.rightBarButtonItem = editButton;
}
-(IBAction)editButtonPressed:(UIBarButtonItem *)sender
{
if ([sender.title isEqualToString:#"Fine"]) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[self.model.dataSource count] - 1 inSection:0];
MemoViewCell *cell = (MemoViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
[cell.bodyLabel resignFirstResponder];
}
}
-(void)insertNewRow:(UIGestureRecognizer *)gestureRecognizer
{
CGPoint point = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:point];
if (indexPath == nil) {
[self.model addObject];
[self.tableView reloadData];
indexPath = [NSIndexPath indexPathForRow:[self.model rowsCount] - 1 inSection:0];
}
[self.navigationItem.rightBarButtonItem setTitle:#"Fine"];
MemoViewCell *cell = (MemoViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
[cell.bodyLabel becomeFirstResponder];
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(contentSizeCategoryChanged:) name:UIContentSizeCategoryDidChangeNotification object:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
-(void)contentSizeCategoryChanged:(NSNotification *)notification
{
[self.tableView reloadData];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.model.dataSource count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MemoViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if ([self.model.dataSource count] > 0) {
NSDictionary *dataSourceItem = [self.model.dataSource objectAtIndex:indexPath.row];
cell.bodyLabel.text = [dataSourceItem valueForKey:#"body"];
}
cell.bodyLabel.delegate = self;
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *reuserIdentifier = CellIdentifier;
if ([self.model.dataSource count] > 0) {
MemoViewCell *cell = [self.offscreenCells objectForKey:reuserIdentifier];
if (!cell) {
cell = [[MemoViewCell alloc] init];
[self.offscreenCells setObject:cell forKeyedSubscript:reuserIdentifier];
}
[cell updateFonts];
NSDictionary *dataSourceItem = [self.model.dataSource objectAtIndex:indexPath.row];
cell.bodyLabel.text = [dataSourceItem valueForKey:#"body"];
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
cell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds));
[cell setNeedsLayout];
[cell layoutIfNeeded];
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
height += 1;
CGFloat toReturn = height + [self measureHeightOfUITextView:cell.bodyLabel] - 30;
NSLog(#"Height for Row %li is %f", (long)indexPath.row, toReturn);
return toReturn;
} else {
return 44.0;
}
}
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 44.0;
}
/*
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
MemoViewCell *cell = (MemoViewCell *)[tableView cellForRowAtIndexPath:indexPath];
cell.bodyLabel.userInteractionEnabled = YES;
[cell.bodyLabel becomeFirstResponder];
}
*/
#pragma mark - Text View Delegate
- (void)textViewDidBeginEditing:(UITextView*)textView
{
MemoViewCell* cell = (MemoViewCell *)[self parentCellFor:textView];
if (cell)
{
NSIndexPath* indexPath = [self.tableView indexPathForCell:cell];
currentIndexPath = indexPath;
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
}
/*
-(BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
MemoViewCell *cell = (MemoViewCell *)[self.tableView cellForRowAtIndexPath:currentIndexPath];
[cell.bodyLabel becomeFirstResponder];
[self.tableView selectRowAtIndexPath:currentIndexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
return YES;
}
*/
- (UITableViewCell*)parentCellFor:(UIView*)view
{
if (!view)
return nil;
if ([view isMemberOfClass:[MemoViewCell class]])
return (UITableViewCell*)view;
return [self parentCellFor:view.superview];
}
-(void)textViewDidChange:(UITextView *)textView
{
NSMutableDictionary *dataSourceItem = [self.model.dataSource objectAtIndex:currentIndexPath.row];
[dataSourceItem setObject:textView.text forKey:#"body"];
[self.model.dataSource replaceObjectAtIndex:currentIndexPath.row withObject:dataSourceItem];
if ([textView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height != textView.frame.size.height) {
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
}
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
return YES;
}
- (CGFloat)measureHeightOfUITextView:(UITextView *)textView
{
if ([textView respondsToSelector:#selector(snapshotViewAfterScreenUpdates:)])
{
CGRect frame = textView.bounds;
UIEdgeInsets textContainerInsets = textView.textContainerInset;
UIEdgeInsets contentInsets = textView.contentInset;
CGFloat leftRightPadding = textContainerInsets.left + textContainerInsets.right + textView.textContainer.lineFragmentPadding * 2 + contentInsets.left + contentInsets.right;
CGFloat topBottomPadding = textContainerInsets.top + textContainerInsets.bottom + contentInsets.top + contentInsets.bottom;
frame.size.width -= leftRightPadding;
frame.size.height -= topBottomPadding;
NSString *textToMeasure = textView.text;
if ([textToMeasure hasSuffix:#"\n"])
{
textToMeasure = [NSString stringWithFormat:#"%#-", textView.text];
}
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
NSDictionary *attributes = #{ NSFontAttributeName: textView.font, NSParagraphStyleAttributeName : paragraphStyle };
CGRect size = [textToMeasure boundingRectWithSize:CGSizeMake(CGRectGetWidth(frame), MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributes
context:nil];
CGFloat measuredHeight = ceilf(CGRectGetHeight(size) + topBottomPadding);
return measuredHeight;
}
else
{
return textView.contentSize.height;
}
}
#end
With this code (insertNewRow:) i first create a new object on dataModel, i reload the data to setup all the table and next i make the first responder my last added UITextView.
On textViewDidChange: delegate i update the table to expand the row(s) to the UITextViewContent.
All works fine if i have at least 2 rows. If i have only one row, all rows assume all the same width.
If your cell's height is fixed then just use this method with return.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
but if your cell's height is dynamic then you need to do some calculation and then return the correct height for the cell.
Related
I have a method setting up value for table view for multi-selection row
- (id)initWithTitle:(NSString *)aTitle options:(NSArray *)aOptions matchingArray:(NSArray *)matchArray xy:(CGPoint)point size:(CGSize)size isMultiple:(BOOL)isMultiple
{
isMultipleSelection=isMultiple;
float height = MIN(size.height, DROPDOWNVIEW_HEADER_HEIGHT+[aOptions count]*44);
CGRect rect = CGRectMake(point.x, point.y, size.width, height);
if (self = [super initWithFrame:rect])
{
self.backgroundColor = [UIColor clearColor];
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOffset = CGSizeMake(2.5, 2.5);
self.layer.shadowRadius = 2.0f;
self.layer.shadowOpacity = 0.5f;
_kTitleText = [aTitle copy];
_kDropDownOption = #[#"India",#"Swaziland",#"Africa",#"Australlia",#"Pakistan",#"Srilanka",#"Mexico",#"United Kingdom",#"United States",#"Portugal"];
_kMatchingArray = #[#"United States",#"Swaziland"];
finalarray=[[NSMutableArray alloc]init];
for(int i = 0;i<[_kMatchingArray count];i++)
{
for(int j= 0;j<[_kDropDownOption count];j++)
{
if([[_kMatchingArray objectAtIndex:i] isEqualToString:[_kDropDownOption objectAtIndex:j]])
{
NSLog(#"%d",j);
NSString *str = [NSString stringWithFormat:#"%d",j];
[finalarray addObject:str];
}
else {
}
}
}
NSLog(#"finalArray:%#",finalarray);
// NSLog(#"%#",_kMatchingArray);
self.arryData=[[NSMutableArray alloc]init];
_kTableView = [[UITableView alloc] initWithFrame:CGRectMake(DROPDOWNVIEW_SCREENINSET,
DROPDOWNVIEW_SCREENINSET + DROPDOWNVIEW_HEADER_HEIGHT,
rect.size.width - 2 * DROPDOWNVIEW_SCREENINSET,
rect.size.height - 2 * DROPDOWNVIEW_SCREENINSET - DROPDOWNVIEW_HEADER_HEIGHT - RADIUS)];
_kTableView.separatorColor = [UIColor colorWithWhite:1 alpha:.2];
_kTableView.separatorInset = UIEdgeInsetsZero;
_kTableView.backgroundColor = [UIColor clearColor];
_kTableView.dataSource = self;
_kTableView.delegate = self;
[self addSubview:_kTableView];
if (isMultipleSelection) {
UIButton *btnDone=[UIButton buttonWithType:UIButtonTypeCustom];
[btnDone setFrame:CGRectMake(rect.origin.x+182,rect.origin.y-45, 82, 31)];
[btnDone setImage:[UIImage imageNamed:#"done#2x.png"] forState:UIControlStateNormal];
[btnDone addTarget:self action:#selector(Click_Done) forControlEvents: UIControlEventTouchUpInside];
[self addSubview:btnDone];
}
}
return self;
}
using this i have create a tableview fetching the values
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_kDropDownOption count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cel lForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentity = #"DropDownViewCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentity];
cell = [[DropDownViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentity];
NSInteger row = [indexPath row];
// NSIndexPath *selectedIndexPath = [finalarray addObject:indexPath.row];
UIImageView *imgarrow=[[UIImageView alloc]init ];
NSLog(#"aray:%#",self.arryData);
if([self.arryData containsObject:indexPath]){
imgarrow.frame=CGRectMake(230,2, 27, 27);
imgarrow.image=[UIImage imageNamed:#"check_mark#2x.png"];
} else
imgarrow.image=nil;
[cell addSubview:imgarrow];
cell.textLabel.text = [_kDropDownOption objectAtIndex:row] ;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if (isMultipleSelection) {
if([self.arryData containsObject:indexPath]){
[self.arryData removeObject:indexPath];
} else {
[self.arryData addObject:indexPath];
}
[tableView reloadData];
} else {
if (self.delegate && [self.delegate respondsToSelector:#selector(DropDownListView:didSelectedIndex:)]) {
[self.delegate DropDownListView:self didSelectedIndex:[indexPath row]];
}
// dismiss self
[self fadeOut];
}
}
I have two array one have total records of the tableview and another one have initially selected values.I have compare the two arrays and get matching indexpath. My problem was how to set check mark image on matched values row?
if ([_strProIDNS isEqualToString:strUNAssignNS])
{
tblViewCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
tblViewCell.accessoryType = UITableViewCellAccessoryNone;
i'm using a tableview to load datas from my college db, the table load the tablecell normally... but when i scroll down the table the name of the discipline goes well but the grade is showing up one on top of above
why is that?
#import "NFMainViewController.h"
#import "NFData.h"
#interface NFMainViewController ()
#end
#implementation NFMainViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
data = [[NFData getData] objectForKey:#"data"];
cursoData = nil;
cursosView = [[UIViewController alloc] init];
[cursosView setTitle:#"Cursos"];
cursosTable = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds];
[cursosTable setDelegate:self];
[cursosTable setDataSource:self];
[cursosView.view addSubview:cursosTable];
[self pushViewController:cursosView animated:NO];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - TableView delegates
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if (tableView == cursosTable) {
return [data count];
} else {
return [cursoData count];
}
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
static NSString *ident = #"headerIdent";
UITableViewHeaderFooterView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:ident];
if (view == nil) {
view = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:ident];
}
if (tableView == cursosTable) {
view.textLabel.text = [[data objectAtIndex:section] objectForKey:#"unidade"];
} else {
NSDictionary *temp = [cursoData objectAtIndex:section];
view.textLabel.text = [NSString stringWithFormat:#"%#ยบ/%#", [temp objectForKey:#"semestre"], [temp objectForKey:#"ano"]];
}
return view;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == cursosTable) {
return [[[data objectAtIndex:section] objectForKey:#"cursos"] count];
} else {
return [[[cursoData objectAtIndex:section] objectForKey:#"disciplinas"] count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ident = #"cellIdent";
UITableViewCell *view = [tableView dequeueReusableCellWithIdentifier:ident];
if (view == nil) {
view = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ident];
}
if (tableView == cursosTable) {
view.textLabel.text = [[[[data objectAtIndex:indexPath.section] objectForKey:#"cursos"] objectAtIndex:indexPath.row] objectForKey:#"curso"];
} else {
UIFont *font = [UIFont fontWithName:#"Arial" size:10.0f];
view.textLabel.font = font;
view.selectionStyle = UITableViewCellSelectionStyleNone;
NSDictionary *temp = [[[cursoData objectAtIndex:indexPath.section] objectForKey:#"disciplinas"] objectAtIndex:indexPath.row];
view.textLabel.text = [temp objectForKey:#"disciplina"];
CGRect notaRect = view.bounds;
notaRect.origin.x = notaRect.size.width - 70.0f;
notaRect.size.width = 50.0f;
UILabel *nota = [[UILabel alloc] initWithFrame:notaRect];
nota.textAlignment = NSTextAlignmentRight;
nota.font = font;
nota.text = [temp objectForKey:#"nota"];
[view addSubview:nota];
CGRect labelRect = view.textLabel.frame;
labelRect.size.height -= 60;
view.textLabel.frame = labelRect;
CGRect progRect = view.bounds;
progRect.origin.x += 6.0f;
progRect.size.width -= 12.0f;
progRect.origin.y += progRect.size.height - 6.0f;
progRect.size.height = 5.0f;
UIProgressView *prog = [[UIProgressView alloc] initWithFrame:progRect];
int faltas = [[temp objectForKey:#"faltas"] intValue];
int maximo = [[temp objectForKey:#"maximo"] intValue];
float value = 1.0f * faltas / maximo;
if (value > 1.0f) {
prog.progressTintColor = [UIColor blackColor];
} else if (value == 1.0f) {
prog.progressTintColor = [UIColor redColor];
} else if (value >= 0.7f) {
prog.progressTintColor = [UIColor yellowColor];
}
[prog setProgress:value];
[view addSubview:prog];
}
return view;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == cursosTable) {
cursoData = [[[[data objectAtIndex:indexPath.section] objectForKey:#"cursos"] objectAtIndex:indexPath.row] objectForKey:#"epocas"];
notasView = [[UIViewController alloc] init];
[notasView setTitle:#"Disciplinas"];
notasTable = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds];
[notasTable setDelegate:self];
[notasTable setDataSource:self];
[notasView.view addSubview:notasTable];
[self pushViewController:notasView animated:YES];
}
}
#end
Your nota UILabel is created each time a UITableViewCell is dequeued. So the first time the tableview loads everything is fine. Then when you start scrolling, your code reuse cells with the nota label already created, but you add another label on top of it. You need to reuse the label previously created.
The best way is to create a UITableViewCell subclass with a nota property for instance.
I add a simple UITableView to my project,and every cell include a UITextField with clearButtonMode = UITextFieldViewModeAlways.
but strange issue occurs .when I reloadData,some textfield don't show clear button.
so I grab the part and build a sample and never find this issue.
I just wonder is some property has a effect to the textField.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"userIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier];
}
for (UIView *sv in cell.contentView.subviews) {
[sv removeFromSuperview];
}
UITextField *tf = [[UITextField alloc] initWithFrame:cell.bounds];
tf.text = [self.tb_data[indexPath.row];
tf.rightViewMode = UITextFieldViewModeAlways;
tf.clearButtonMode = UITextFieldViewModeAlways;
tf.tag = indexPath.row+100;
tf.delegate = self;
[[cell contentView] addSubview:tf];
return cell;
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if (textField.tag >= 100) {
return NO;
}
return YES;
}
- (BOOL)textFieldShouldClear:(UITextField *)textField
{
if (textField.tag >= 100) {
[self.tb_data removeObjectAtIndex:textField.tag-100];
[self.tb beginUpdates];
[self.tb deleteRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:textField.tag-100 inSection:0]] withRowAnimation:UITableViewRowAnimationLeft];
[UIView animateWithDuration:0.3
animations:^{
CGRect frame = self.tb.frame;
frame.size.height = 40*self.tb_data.count;
self.tb.frame = frame;
}];
[self.tb endUpdates];
[self.tb reloadData];
}
return YES;
}
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.
I am trying to dynamically resize some UITableViewCell's based on the height of UITextView's contained within them.
There's loads of solutions to this by keeping a pointer to the UITextView and getting it's content size in heightForRowAtIndexPath however when the whole table is created dynamically with an unknown number of rows and an unknown number of them rows contain UITextView's this just isn't possible.
It would be easy if I could call the cell in question during heightForRowAtIndexPath but that causes an infinite loop and crash as this method is called before any cell's are even created.
Any other solutions?
I am using a UITableViewCell subclass for my cell like this:
- (void)initalizeInputView {
// Initialization code
self.selectionStyle = UITableViewCellSelectionStyleNone;
self.textView = [[UITextView alloc] initWithFrame:CGRectZero];
self.textView.autocorrectionType = UITextAutocorrectionTypeDefault;
self.textView.autocapitalizationType = UITextAutocapitalizationTypeNone;
self.textView.textAlignment = NSTextAlignmentRight;
self.textView.textColor = [UIColor lightBlueColor];
self.textView.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:17];
self.textView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
self.textView.keyboardType = UIKeyboardTypeDefault;
[self addSubview:self.textView];
self.textView.delegate = self;
}
- (BOOL)resignFirstResponder {
if (_delegate && [_delegate respondsToSelector:#selector(tableViewCell:didEndEditingWithLongString:)]) {
[_delegate tableViewCell:self didEndEditingWithLongString:self.stringValue];
}
return [super resignFirstResponder];
}
- (void)setKeyboardType:(UIKeyboardType)keyboardType
{
self.textView.keyboardType = keyboardType;
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self initalizeInputView];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self initalizeInputView];
}
return self;
}
- (void)setSelected:(BOOL)selected {
[super setSelected:selected];
if (selected) {
[self.textView becomeFirstResponder];
}
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if (selected) {
[self.textView becomeFirstResponder];
}
}
- (void)setStringValue:(NSString *)value {
self.textView.text = value;
}
- (NSString *)stringValue {
return self.textView.text;
}
- (void)textViewDidBeginEditing:(UITextView *)textView
{
// For keyboard scroll
UITableView *tableView = (UITableView *)self.superview;
AppSetupViewController *parent = (AppSetupViewController *)_delegate;
parent.activeCellIndexPath = [tableView indexPathForCell:self];
}
- (void)textViewDidChange:(UITextView *)textView
{
if (textView.contentSize.height > contentRowHeight) {
contentRowHeight = textView.contentSize.height;
UITableView *tableView = (UITableView *)self.superview;
[tableView beginUpdates];
[tableView endUpdates];
[textView setFrame:CGRectMake(0, 0, 300.0, textView.contentSize.height)];
}
}
- (void)textViewDidEndEditing:(UITextView *)textView
{
if (_delegate && [_delegate respondsToSelector:#selector(tableViewCell:didEndEditingWithLongString:)]) {
[_delegate tableViewCell:self didEndEditingWithLongString:self.stringValue];
}
UITableView *tableView = (UITableView *)self.superview;
[tableView deselectRowAtIndexPath:[tableView indexPathForCell:self] animated:YES];
}
- (void)layoutSubviews {
[super layoutSubviews];
CGRect editFrame = CGRectInset(self.contentView.frame, 10, 10);
if (self.textLabel.text && [self.textLabel.text length] != 0) {
CGSize textSize = [self.textLabel sizeThatFits:CGSizeZero];
editFrame.origin.x += textSize.width + 10;
editFrame.size.width -= textSize.width + 10;
self.textView.textAlignment = NSTextAlignmentRight;
} else {
self.textView.textAlignment = NSTextAlignmentLeft;
}
self.textView.frame = editFrame;
}
Which is created in cellForRowAtIndexPath like this:
else if ([paramType isEqualToString:#"longString"]) {
MyIdentifier = #"AppActionLongString";
LongStringInputTableViewCell *cell = (LongStringInputTableViewCell *)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
cell.textLabel.text = [[[_selectedAction objectForKey:#"parameters"] objectAtIndex:indexPath.row] objectForKey:#"name"];
cell.params = [[_selectedAction objectForKey:#"parameters"] objectAtIndex:indexPath.row];
cell.textView.text = [results objectAtIndex:indexPath.row];
return cell;
}
Simply passing back the height to a variable in my ViewController is no good because like I said, there could be several of these cells within the table.
Thanks
Use this method to dynamically resize your tableviewCell. First store the user input in NSMutable Array and after that reload table. Hope it will help you.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *msg =[self.messages objectAtIndex:indexPath.row];
CGSize textSize = { 120, 10000.0 };
CGSize size = [msg sizeWithFont:[UIFont systemFontOfSize:15]
constrainedToSize:textSize
lineBreakMode:UILineBreakModeWordWrap];
return size.height+20;
}
I needed a dynamic table view cell height based on the amount of text to be displayed in that cell. I solved it in this way:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!isLoading)
{
if ([self.conditionsDataArray count]>0)
{
Conditions *condition =[self.conditionsDataArray objectAtIndex:indexPath.row];
int height;
UITextView *textview = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 236, 0)]; //you can set your frame according to your need
textview.text = condition.comment;
textview.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[tableView addSubview:textview];
textview.hidden = YES;
height = textview.contentSize.height;
NSLog(#"TEXT VIEW HEIGHT %f", textview.contentSize.height);
[textview removeFromSuperview];
[textview release];
return height;
}
return 55; //Default height, if data is in loading state
}
Notice that the Text View has been added as Subview and then made hidden, so make sure you add it as SubView otherwise it's height will not be considered.
It would be easy if I could call the cell in question during heightForRowAtIndexPath but that causes an infinite loop and crash as this method is called before any cell's are even created. Any other solutions?
You can. I would guess you're attempting to call cellForRowAtIndexPath, which will cause an infinite loop. But you should rather be dequeuing the cell directly by calling dequeueReusableCellWithIdentifier.
See the table view delegate implementation of TLIndexPathTools. The heightForRowAtIndexPath method looks like this:
(EDIT Initially forgot to include the method prototypeForCellIdentifier that actually dequeues the cell.)
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
id item = [self.dataModel itemAtIndexPath:indexPath];
NSString *cellId = [self cellIdentifierAtIndexPath:indexPath];
if (cellId) {
UITableViewCell *cell = [self prototypeForCellIdentifier:cellId];
if ([cell conformsToProtocol:#protocol(TLDynamicSizeView)]) {
id<TLDynamicSizeView> v = (id<TLDynamicSizeView>)cell;
id data;
if ([item isKindOfClass:[TLIndexPathItem class]]) {
TLIndexPathItem *i = (TLIndexPathItem *)item;
data = i.data;
} else {
data = item;
}
CGSize computedSize = [v sizeWithData:data];
return computedSize.height;
} else {
return cell.bounds.size.height;
}
}
return 44.0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView prototypeForCellIdentifier:(NSString *)cellIdentifier
{
UITableViewCell *cell;
if (cellIdentifier) {
cell = [self.prototypeCells objectForKey:cellIdentifier];
if (!cell) {
if (!self.prototypeCells) {
self.prototypeCells = [[NSMutableDictionary alloc] init];
}
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
//TODO this will fail if multiple tables are being used and they have
//overlapping identifiers. The key needs to be unique to the table
[self.prototypeCells setObject:cell forKey:cellIdentifier];
}
}
return cell;
}
This uses a protocol TLDynamicSizeView that any cell can implement to have it's height calculated automatically. Here is a working example project. The cell's implementation of the protocol looks like this:
#implementation DynamicHeightCell
- (void)awakeFromNib
{
[super awakeFromNib];
self.originalSize = self.bounds.size;
self.originalLabelSize = self.label.bounds.size;
}
- (void)configureWithText:(NSString *)text
{
self.label.text = text;
[self.label sizeToFit];
}
#pragma mark - TLDynamicSizeView
- (CGSize)sizeWithData:(id)data
{
[self configureWithText:data];
//the dynamic size is calculated by taking the original size and incrementing
//by the change in the label's size after configuring
CGSize labelSize = self.label.bounds.size;
CGSize size = self.originalSize;
size.width += labelSize.width - self.originalLabelSize.width;
size.height += labelSize.height - self.originalLabelSize.height;
return size;
}
#end
just comment
if (cell == nil)
Hope, this will help you.