SizetoFit versus UIViewAutoresizingFlexibleHeight. What is the difference? - ios

I had always been told that if I have a UILabel with dynamic text content in it that I should use SizeToFit as that would adjust the UILabel properly. I used sizeToFit but it was messing up my text labels that were on a UITableViewCell after I did a scroll. However on initial screen load, they would appear fine.
After messing with it for a couple of hours I read somewhere that someone else had the same issue and that instead of SizeToFit they used the following two lines:
cell.message.lineBreakMode = UILineBreakModeWordWrap;
cell.message.autoresizingMask = UIViewAutoresizingFlexibleHeight;
and it would work. Well I did and my UILabels are perfect. However I am still curious in understanding why so?
so now my code looks like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MessagesCustomViewCell";
MessagesCustomViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"MessagesCustomViewCell_iPhone" owner:self options:nil];
cell = [nib objectAtIndex:0]; //you can also loop thru or manually remember positions
}
NSArray * discussion = [self.messages objectAtIndex:indexPath.row];
cell.author.text = [discussion valueForKeyPath:#"author.name"];
cell.message.text = [discussion valueForKey:#"text"]; //DYNAMIC VARIABLE SIZED TEXT
cell.message.lineBreakMode = UILineBreakModeWordWrap;
cell.message.autoresizingMask = UIViewAutoresizingFlexibleHeight;
return cell;
}

sizeToFit
behavior:care about its content over superview's size
send sizeToFit to a UILabel without [yourLabel setNumberOfLines:0] will make the Label as wide as possible to fit it's text. While with [yourLabel setNumberOfLines:0] your label will break it's text to mutiple lines according it's width, but this will make it's height as large as possible to fit in it's text, it does not care about it's superview's bounds.
autoResizingMask
behavior:care about superview's size over its content
If a UIlabel's autoResizingMask is set, once it's superview's bounds is change, it will change it's frame first, then it checks "Can i put more text in my rect?" base on it's relative properties(numberOfLines, font,...).

Related

Displaying image in sliding menu

I have small question. How to display profile picture and UserFullName and State and Country in single label dynamically from a service in sliding menu like below attached image. TIA
Design tablecell like this or you can also design UIView in sidebar like same.
Programmatically set corner radius of image so it's look round.
Yes you can set all in one label expect to imageview
do this
[_demolabel setText:[NSString stringWithFormat:#" UserFullName \n State Country"]];
And apply your suitable logic for label height and width.
Image you can not add in Label, you need a separate outlet for Image.
Displaying in single label is bit tricky. You have to use NSAttributted Text. After reading the name of the user needed to append a \n to truncate the next line data.
label.numberOFLines = 0; (you have to set this for label)
Best option Use two label one for User name and next one is for location give proper auto layout and spacing between them, then you are done.
Use Custom Cell you can get the image,name,state and country
First you need to create Custom UITableView Cell.In xib file you need to set ImageView,name label and staecountry label also connect(drag in .h).
please import the Quartzcore framework for forming circle
#import <QuartzCore/QuartzCore.h>
in TableView DataSource Methods
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return yourArray.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomTableViewCell *cell = (CustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"cell"];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.imgViewDetail.image = [UIImage imageNamed:#"imagename.png"];
cell.imgView.layer.borderWidth = 2.0;
cell.imgView.layer.cornerRadius = cell.yourImageView.frame.size.height /2;
cell.imgView.layer.masksToBounds = YES;
cell.labelName.text = #"James Stevens";
cell.labelStateCountry.text = [NSString stringWithFormat:#"%#%#",#"Sydney",#"Australia"];
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 80;
}
Important - You have to give imageView width and height as 200,200 or 100,100 or 50,50....whatever you want to give equal width and height when you set imageView as circle
You can't set UserFullName, State and Country in single label. You need to use two labels, set image like your attached pic, and round corners.
For example:
Imageview.layer.cornerRadius=10;
[Imageview.layer setMasksToBounds:YES];

iOS 8 - autoresizing cells don't always show all label text

basically I'm using autoresizing custom table view cells to display data on a table view and they resize perfectly, usually. The cells have a UILabel on them to display the data and the cells autoresize if the devices text size is changed. I'm sometimes having troubles with the cells autoresizing to show all of the UILabel's text. For example if the text size is medium sized, it sometimes doesn't fully display all the text of a longer label, it will show most of it then show "..." but if I increase or decrease the text size it will show it all but it might do the same thing for a different cell.
Any suggestions? Here's my code that calls the autoresize:
- (void)viewDidAppear:(BOOL)animated
{
[self.tableView reloadData];
[self retrieveFromParse];
self.tableView.estimatedRowHeight = 100;
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
and to autoresize depending on text size:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
_cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (_cell == nil)
{
_cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
PFObject *object = [_postsArray objectAtIndex:indexPath.row];
NSString *nameString = [object objectForKey:#"Name"];
_cell.cellLabel.text = [NSString stringWithFormat:#"Posted by %#", nameString];
_cell.cellPostLabel.text = [NSString stringWithFormat:#" %#", [object objectForKey:#"Post"]];
//The following lines are to auto resize when the text size is changed
_cell.cellLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
_cell.cellPostLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
return _cell;
}
Try using autoresizingMask if that helps
_cell.cellLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
Auto Layout has trouble figuring out how to draw multi-line labels if you don't set preferredMaxLayoutWidth on each one. The trouble is finding out what value to use since tables can change widths across the various iPhone & iPad devices, orientations, etc. To fix this, I usually subclass UILabel to override layoutSubviews:
- (void)layoutSubviews {
[super layoutSubviews]; // 1
self.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds); // 2
[super layoutSubviews]; // 3
}
The first call to super correctly determines how wide the label should be.
Using the correct width, set preferredMaxLayoutWidth to the correct value.
Do another layout pass to render the label with its final and correct properties.
If you use autolayout, I have solution for you. I'm not sure that this is the perfect one, but here it is (Swift):
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
// configure your cell
cell.layoutIfNeeded()
}
P.S. if I doesn't use layoutIfNeeded and if I rotate my device and turn it back, to portrait, label layouts as it must e.g. 2 or more strings in one cell.
Didn't find reason why this occur, because (I use more that one prototype cell in my project) other type cells is okay, but their labels have simular constraints and settings.
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 66
}
works just fine on 8.4.1 for UITableViewCellStyle.Default cells

Creating a Label in each of my custom cell in cellForRowIndexPath

I am trying to create a label in each of my customCells. In cellForRowIndexPath, I have:
EDIT:
static NSString *checkInTableIdendifier = #"ChatCell";
cell = (ChatTableViewCell *)[tableView dequeueReusableCellWithIdentifier:checkInTableIdendifier];
if (cell == nil){
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ChatTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
NSAttributedString *title;
title = [[NSAttributedString alloc] initWithString:[self.savedMsgs objectAtIndex:indexPath.row] attributes:#{ NSFontAttributeName : [UIFont fontWithName:#"Noteworthy-Bold" size:12], NSUnderlineStyleAttributeName : #1 , NSStrokeColorAttributeName : [UIColor blackColor]}]; //1
UILabel *label;
label = [[UILabel alloc] initWithFrame:CGRectMake( (self.view.bounds.size.width - title.size.width) / 2.0f, 40.0f, title.size.width, title.size.height)]; //2
label.attributedText = title; //3
[cell addSubview:label]; //4
The label will all end up in the same point overlapping each other because of line 2. How can I represent the origin of the label generated according to each respective cell?
The method you are using to generate cells, 'dequeueReusableCellWithIdentifier' can return a cell that has already been used before. When you add your labels etc after getting the cell, you are adding labels on top of labels that are already there.
The easiest way to handle cell reuse is to create a UITableViewCell subclass and an associated xib. After this ViewController is created and the tableView is accessible (viewDidLoad, usually) register the nib for the cell to the tableView. Then when you dequeue the cell, you need only to set the text values on the labels that are already there.
An aside, UITableView had a newer better method for dequeuing cells that takes an index path and always returns a cell so you don't need to nil check it. I would switch to that if you don't need to support iOS 6.
You should use the cell's bounds, not self.view's to position the label. Be careful as the frame might change after the cell has been created, so it's recommended to use auto layout to ensure the label is always positioned when you want it to be in respect to the cell.
Also, remember that the cell get reused in which case you might end up adding the label multiple times.
To mitigate both issues, subclass the cell and design it in the accompanying xib.

ios autolayout issue with UILable text padding

I have a custom class created for custom cells for my table view. There's UILabel for messages. I'm using storyboard to set the constraints, pinning the label to the top and right side of the table cell, I found that doing this causes the label to resize to fit the content. Now I can't figure out how to add padding to the label because anything done in cellForRowAtIndexPath doesn't work since auto layout is selected. I've seen many examples that do CGRectMake with float values but they don't work and I think it's because of auto layout. Is there any solution for this?
I'm not even sure what code to show for this...so here goes something:
How I'm getting the height of the message...the cell is set for 220 width...cellForRowAtIndexPath:
static NSString *cellIdentifier = #"chatCell";
ChatCell *cell = (ChatCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[ChatCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
info = [receivedData objectAtIndex:indexPath.row];
message = [info objectForKey:#"message"];
CGSize constraint = CGSizeMake(220, 2000);
CGRect rect = [message boundingRectWithSize:constraint options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:[UIFont systemFontOfSize:12.0f]} context:nil];
CGSize size = rect.size;
With that information, I set the table row heights in heightForRowAtIndexPath. But adjusting the frame of the label cell.messageLabel gives me no result. Here's something else I tried in the cellForRowAtIndexPath:
UIView *messageFrame = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 220, size.height)];
[messageFrame addSubview:cell.messageLabel];
[cell addSubview:messageFrame];
But this is the result in the simulator:
Everything is moved up and the whole text doesn't show. Is there a simple solution for this or do I have to rethink my entire code?
ANSWER:
What I did was add a UIView in storyboard and put it's constraints to the bottom of the cell. Since I was adjusting the cell height based on content bounds function from ios7, setting the constraint to the bottom automatically stretched the UIView all the way to the bottom. Playing with the message label width, I got to have padding. Hope this helps someone.

UITableViewCell with UIImage, width not updating on initial displayed cells

I would like to dynamically adjust the width of a UIImage inside of a UITableViewCell, I'm using the storyboard to design the UITableViewCell, I just added a label and an image, the properties get updated correctly, I'm even loading the value of the width into the label to show that it's the correct value, for the image, I'm loading a background image that I want to repeat, but the image won't update the width initially, if I scroll up and down, the images are shown as expected, here's the code for the cellForRowAtIndexPath, I've also tried to put the code on the willDisplayCell method, same result
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"mycustomcell"];
int r = [[data objectAtIndex:indexPath.row] intValue];
UIImageView *img = (UIImageView *)[cell viewWithTag:2];
img.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"some_img" ofType:#"png"]]];
CGRect frame = img.frame;
frame.size.width = r*16;
img.frame = frame;
int n = img.frame.size.width;
UILabel *label = (UILabel *)[cell viewWithTag:1];
label.text = [NSString stringWithFormat:#"custom %d", n];
[cell setNeedsDisplay];
return cell;
}
I just want this to work initially as it works after scrolling, thoughts?
The dynamic resizing of contents of a tableview cell is a well known problem. While there are kludgy workarounds, I believe proper solution depends upon whether you're using autolayout or not:
If using auto layout, make sure that your cell's image view has a width constraint, and then you can change the constraint's constant:
for (NSLayoutConstraint *constraint in img.constraints)
{
if (constraint.firstAttribute == NSLayoutAttributeWidth)
constraint.constant = r*16;
}
Frankly, I'd rather use a custom UITableViewCell subclass and have an IBOutlet for the width constraint (e.g. imageWidthConstraint), and it saves you from having to enumerate through the constraints to find the right one, and you can simply:
cell.imageWidthConstraint.constant = r*16;
If not using auto layout, you should subclass UITableViewCell, use that for your cell prototype's base class, and then override layoutSubviews, and resize the image view there. See Changing bounds of imageView of UITableViewCell.
Regardless of which approach you adopt, using a UITableViewCell subclass eliminates the need to use viewForTag construct, which makes the view controller code a little more intuitive.
argh, removing Auto Layout fixed the problem

Resources