Dynamic Height for UITableViewCell using custom Font - objective-c

I've been trying to make a dynamic table view cell to use in a chat
You can see that actually im using a constant height for the cell(88) but if the text is longer, it will be awful
I'm using the font Muli and that's why I don't know how can I calculate the correct height.
here is my code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 88;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.comunidades count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = (UITableViewCell *)[self.tabla dequeueReusableCellWithIdentifier:#"DM_tab"];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"DM_tab" owner:self options:nil];
cell = (UITableViewCell *)[nib objectAtIndex:0];
}
NSDictionary *comunidad = [self.comunidades objectAtIndex:indexPath.row];
UILabel *textosender=(UILabel *) [cell viewWithTag:2];
textosender.text=[comunidad objectForKey:#"nombre"];
textosender.font = [UIFont fontWithName:#"Muli-Light" size:14];
UILabel *textomio= (UILabel *) [cell viewWithTag:3];
textomio.text=[comunidad objectForKey:#"nombre"];
textomio.font = [UIFont fontWithName:#"Muli-Light" size:14];
NSString *tipo=[comunidad objectForKey:#"sender"];
NSUserDefaults *defs=[NSUserDefaults standardUserDefaults];
if([tipo isEqualToString:[defs objectForKey:#"username"]]){
UIImageView* img = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"A_DM_fondo#2x.png"]];
[cell setBackgroundView:img];
textosender.hidden=YES;
textomio.hidden=NO;
NSString *detallemio=[comunidad objectForKey:#"mensaje"];
[textomio setText:detallemio];
}
else{
UIImageView* img = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"N_DM_fondo#2x.png"]];
[cell setBackgroundView:img];
textosender.hidden=NO;
textomio.hidden=YES;
NSString *detallemio=[comunidad objectForKey:#"mensaje"];
[textosender setText:detallemio];
}
return cell;
}
Thanks

Replace the 88 in the tableView:heightForRowAtIndexPath: method with the height you want the particular row to have, calculated using something like the boundingRectWithSize:options:attributes:context: method on NSString.

Related

UiTableView on iPhone showing only first row on iOS 10.0

I am experimenting a weird behavior with the tableView on iPhone only.
The problem is that the UITableView which updates automatically while loading data would show on iPhone only the first row and as I scroll down the other rows start appearing, This behavior started with iOS 10.0 and only on iPhone. On iPad it works correctly.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section {
// Return the number of rows in the section.
return [searchResultsArray count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[[NSBundle mainBundle] loadNibNamed:#"searchResultCell" owner:self options:nil];
}
else {
[[NSBundle mainBundle] loadNibNamed:#"searchResultCell~iphone" owner:self options:nil];
}
cell = referenceCell;
self.referenceCell = nil;
self.referenceCell.tag = indexPath.row;
}
NSMutableDictionary *referenceDict = [searchResultsArray objectAtIndex:indexPath.row];
UILabel *label = (UILabel *)[cell viewWithTag:3];
label.text = [referenceDict objectForKey:#"TEXT"];
UIView *cellView = (UIView*)[cell viewWithTag:5];
BOOL colorBack = [[referenceDict objectForKey:#"COLOR"]intValue];
if (colorBack) {
cellView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed: #"light gray.png"]];
}
else {
cellView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed: #"sepia.png"]];
}
cell.textLabel.highlightedTextColor = [UIColor blueColor];
return cell;
}
Test threads in which the code is running inside cellForRowAtIndexPath. I've had similar problems in this method in iOS10 while work with view layer

How to calculate number lines required for text

I know this is going to be a stupid daft simple question but I'm going round in circles.
I have several strings which i want displaying in a uitableview. Some of these strings are very long. I have previously asked how to calculate the cell height, and choose the following answer:
- (CGFloat)cellHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellString = <YOUR MODEL OBJECT>;
NSDictionary *attributes = #{ NSFontAttributeName : [UIFont systemFontOfSize:16.0f] };
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]
initWithString: cellString
attributes:attributes];
CGFloat width = self.tableView.frame.size.width - 32.0f;
CGRect frame = [attributedString boundingRectWithSize:CGSizeMake(width, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin context:nil];
// Add some extra padding to the height
CGFloat height = frame.size.height + 16.0f;
return ceil(height);
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [self cellHeightForRowAtIndexPath:indexPath];
}
how can I get the number of lines required in the uitableview to display the strings.
The best way to actually calculate a cell height is to use a prototype cell for calculating the height.
Add a property to your interface extension:
#interface TableViewController ()
#property (nonatomic, strong) TableViewCell *prototypeCell;
#end
Then lazily load it:
- (TableViewCell *)prototypeCell
{
if (!_prototypeCell)
{
_prototypeCell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Prototype"];
}
return _prototypeCell;
}
Change your -[tableView:cellForRowAtIndexPath:] method to use a -[configureCell:forRowAtIndexPath:] type pattern:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellId" forIndexPath:indexPath];
[self configureCell:cell forRowAtIndexPath:indexPath];
return cell;
}
-(void)configureCell:(TableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
// Set up you cell from your model
}
Now use this method to setup your prototype and then use the height of that for -[tableView:heightForRowAtIndexPath:]:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
[self configureCell:self.prototypeCell forRowAtIndexPath:indexPath];
[self.prototypeCell layoutIfNeeded];
CGSize size = [self.prototypeCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
return ceil(size.height);
}

Making all the text show in a UITableView Cell

I am loading an array into a UITableView and the components of the array are long. What I want to do is customize the cells so that thier lenght will adjust to fit the text but the width will stay the same. Right now what is happening is when the text gets too long it will just write off the cell and you will see this.
I would like to see the text hit the end of the cell and then start a new line.
My code right now looks like this.
#implementation CRHCommentSection
#synthesize observationTable;
NSArray *myArray;
- (void)viewDidLoad
{
myArray = [CRHViewControllerScript theArray];
NSLog(#"%#", myArray);
//NSArray* paths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:1]];
//[observationTable insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationTop];
[observationTable reloadData];
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
NSLog(#" in method 1");
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#" in method 2");
// Return the number of rows in the section.
return [myArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#" in method 3");
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewStylePlain reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [myArray objectAtIndex:indexPath.row];
//cell.textLabel.text = #"Label";
return cell;
}
I also found some code that somebody else wrote for multiple lined cells but don't know how to make it automatic based on the length of my string from the array.
static NSString *CellIdentifier = #"MyCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2
reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = #"Label';
cell.detailTextLabel.text = #"Multi-Line\nText";
cell.detailTextLabel.numberOfLines = 2;
cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
They said that you will also need to return a suitable height for the multi-line cell and that a height of (44.0 + (numberOfLines - 1) * 19.0) should work fine.
Does anyone have any ideas of how to do this?
Thanks.
You will need to work with following methods
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// this method is called for each cell and returns height
NSString * text = #"Your very long text";
CGSize textSize = [text sizeWithFont:[UIFont systemFontOfSize: 14.0] forWidth:[tableView frame].size.width - 40.0 lineBreakMode:NSLineBreakByWordWrapping];
// return either default height or height to fit the text
return textSize.height < 44.0 ? 44.0 : textSize.height;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * cellIdentifier = #"YourTableCell";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
reuseIdentifier:cellIdentifier];
[[cell textLabel] setNumberOfLines:0]; // unlimited number of lines
[[cell textLabel] setLineBreakMode:NSLineBreakByWordWrapping];
[[cell textLabel] setFont:[UIFont systemFontOfSize: 14.0]];
}
[[cell textLabel] setText:#"Your very long text"];
return cell;
}
You want to look at the NSString function -(CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
You will have to include it in your heightForRowAtIndexPath function to determine the right heights.
Also, set the numberOfLines for your label to 0. This allows it to adjust to whatever number of lines is needed.
How about using UITextView in table view cell.
At first, you have to change the height of cell.
Next, you put the UITextView into the cell.
Off course you can do this not by IB but by code.
For me the accepted answer worked by adding the else condition.
In my case, if condition was not getting satisfied as the [tableView dequeueReusableCellWithIdentifier:#"comment"]; was always returning cell which was not nil.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger item = indexPath.item;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"comment"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
reuseIdentifier:#"comment"];
[[cell textLabel] setNumberOfLines:0]; // unlimited number of lines
[[cell textLabel] setLineBreakMode:NSLineBreakByWordWrapping];
[[cell textLabel] setFont:[UIFont systemFontOfSize: 14.0]];
}
// added else condition
else {
[[cell textLabel] setNumberOfLines:0];
[[cell textLabel] setLineBreakMode:NSLineBreakByWordWrapping];
[[cell textLabel] setFont:[UIFont systemFontOfSize: 14.0]];
}
[[cell textLabel] setText:commentsText[item]];
return cell;
}

add background image for sections in UITableView

is it possible to change background image of each sections in uitableview?
I want to add background image for each sections in uitableview
does anyone know how can I do that?
Thanks in advance!
like this picture --> put different background images for wednesday , Thursday and friday separately
Edit I want to add image 1 for wednesday image 2 for Thursday image 3 for friday and .....
how can I specify that ?
Edit
this the code for creating sections header I want to have background also
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if(section == 0)
return #"Monday";
else if(section == 1){
return #"Tuesday";
}else if(section == 2){
return #"Wednesday";
} else if(section == 3){
return #"Thuesday";
} else if(section == 4){
return #"Friday";
} else if(section == 5){
return #"Saturday";
}else
return #"Sunday";
}
You could change the background in the cellForRowAtIndexPath delegate method based on the indexPath, like so:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TaskCellRow";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
int maxRow = 3;
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed: [NSString stringWithFormat: #"background_image%i.png", MIN(indexPath.row, maxRow)]]];
}
else
{
UIImageView *background = (UIImageView *)cell.backgroundView;
background.image = [UIImage imageNamed: [NSString stringWithFormat: #"background_image%i.png", MIN(indexPath.row, maxRow)]];
}
return cell;
}
// To change header backgrounds
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
int maxRow = 3;
UIImageView *headerView = [[UIImageView alloc] initWithImage:[UIImage imageNamed: [NSString stringWithFormat: #"background_image%i.png", MIN(section, maxRow)]]];
return headerView;
}
You would then just create images, numbered for the desired amount header/rows, ie. background_image0.png, background_image1.png, background_image2.png, ... and so forth. The MIN will cap the amount off at the whatever you decide is the max backgrounds. Hope that helps.
EDIT: Changed cellForRowAtIndexPath based on Henri's comments. I overlooked that, thanks! This is for ARC compatibility.
You can use:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
to specify any kind of UIView for a section header. This other delegate method:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
lets you specify the height.
Just alloc/init the UIView in the first one using the table's width and the height from the second method and then add any number of views to it, such as a UIImageView for a background then a label for the title.
Iterating (and mostly correcting) example given by ezekielDFM. Note, this code is not ARC compatible (which previous example may have been).
// To change cell backgrounds
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"TaskCellRow";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
int maxRow = 3;
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
UIImageView *imageView = [[UIImageView alloc] initWithImage: [UIImage imageNamed: [NSString stringWithFormat: #"background_image%i.png", MIN(indexPath.row, maxRow)]]] autorelease];
cell.backgroundView = imageView;
} else {
// Reusing, we need to swap out the image of the background
cell.backgroundView.image = [UIImage imageNamed: [NSString stringWithFormat: #"background_image%i.png", MIN(indexPath.row, maxRow)]];
}
return cell;
}
// To change header backgrounds
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
int maxRow = 3;
UIImageView *headerView = [[[UIImageView alloc] initWithImage:[NSString stringWithFormat:#"background_image%i.png", MIN(section, maxRow)]] autorelease];
return headerView;
}
As i guess it is not possible to change the background image for Table view Sections. If you want to do such a requirement, please try with cell for row as Sections. i.e. for each row treat as section of table & in that add 1 more table view with different tag. It will full your req. or else for each row take

Howto fill UITableView with sections and rows dynamically?

I have some problems with UITableView and sections/rows.
Iam parsing the section names, all row names and row count per section from a xml.
I have 3 NSMutableArrays:
nameArray (with all row names)
sectionArray (all section names)
secCountArray (row count per section)
For the cellForRowAtindexPath to work, do I have to return the rows for the displayed section?
The next step I would do is to build an 2d Array with sections and all rows for each section.
Does anyone knows any better solution?
Here comes the code:
// Customize the appearance of table view cells.
- (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];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Set up the cell
int xmlEntryIndex = [indexPath indexAtPosition: [indexPath length] -1];
//???
cell.textLabel.text = [[theParser.nameArray objectAtIndex: 1]valueForKey:#"name"];
return cell;
}
Thanks!
You could have one _section array and one _row array for the whole tableview.
like your view controller.h file declare array
NSMutableArray *arrSection, *arrRow;
then your view controller.m file paste below code..
- (void)viewDidLoad
{
[super viewDidLoad];
arrSection = [[NSMutableArray alloc] initWithObjects:#"section1", #"section2", #"section3", #"section4", nil];
arrRow = [[NSMutableArray alloc] init];
[arrSection enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSMutableArray *tempSection = [[NSMutableArray alloc] init];
[arrSection enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[tempSection addObject:[NSString stringWithFormat:#"row%d", idx]];
}];
[arrRow addObject:tempSection];
}];
NSLog(#"arrRow:%#", arrRow);
}
#pragma mark - Table view data source
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [arrSection count];
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [arrSection objectAtIndex:section];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[arrRow objectAtIndex:section] count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:nil];
if(!cell)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil];
cell.textLabel.text = [[arrRow objectAtIndex:[indexPath section]] objectAtIndex:[indexPath row]];
return cell;
}
This method does not involve defining and creating your own custom view. In iOS 6 and up, you can easily change the background color and the text color by defining the
- (void)tableView:(UITableView *)tableView
willDisplayHeaderView:(UIView *)view
forSection:(NSInteger)section
delegate method.
For example:
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
// Background color
view.tintColor = [UIColor blackColor];
// Text Color
UITableViewHeaderFooterView *header = (UITableViewHeaderFooterView *)view;
[header.textLabel setTextColor:[UIColor whiteColor]];
// Another way to set the background color
// Note: does not preserve gradient effect of original header
// header.contentView.backgroundColor = [UIColor blackColor];
}
you can see display dynamic section and row
May be helpful for you..
You could have one array for the whole table view. The array contains arrays for every section. Then the cellForRowAtIndexPath could look 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] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
[[cell textLabel] setText: [[[myArray objectAtIndex: indexPath.section] objectAtIndex: indexPath.row]];
return cell;
}
I hope this help you in your problem.
Edit: With the modern Objective-C and ARC I would write this as
- (void)viewDidLoad {
....
[self.tableView registerClass:[MyCellClass class] forCellReuseIdentifier:kMyCellIdentifier];
}
...
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
MyCellClass *cell = [tableView dequeueReusableCellWithIdentifier:kMyCellIdentifier forIndexPath:indexPath];
cell.textLabel.text = myArray[indexPath.section][indexPath.row];
return cell;
}