How to configure iOs UITextViews and UILabels so that their height is determined by their content - iphone

I am basically trying to find the correct way to design a UITableViewCell that has two UITextViews and three UILabels inside it. The two UITextViews have dynamic content and their size cannot be determined until runtime.
I have tried various methods of recalculating the height of my UITextViews based on the content that is loaded in them at runtime, and though very laborious and inane, I have gotten that to work, but they then bleed over the UILabels positioned in the xib below them.
Do I really have to recalculate the y coordinates of every UILabel after calculating the new size of the UITextViews? Is there a way to simply have the elements in the xib 'push' the elements below them down based on their new size?
What is the correct approach to configuring a UITableViewCell with multiple dynamic text views so that my entire application is not comprised of code to calculate heights and coordinates?
Or is the answer that I should not be putting more than one dynamic UITextView in the same UITableViewCell ?

I have used something like this for a cell to calculate its height in
tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
function
CGSize labelSize = [self.comments sizeWithFont:[UIFont fontWithName:#"Verdana" size:17.0]
constrainedToSize:CGSizeMake(280.0f, MAXFLOAT)
lineBreakMode:UILineBreakModeWordWrap];
return labelSize.height + 20;
+20 is for padding.
and also if you are having every cell like the one you mention above, than you can create a class of UITableViewCell with following UIView elements inside it.

iOS doesn't seem to have any sort of flow layout engine -- at least none that I can think of.
If, however, your labels are located at the bottom of your UITableViewCell, you might be able to get away with setting the UILabel's autoresizingMask mask property to UIViewAutoresizingFlexibleBottomMargin so that the UILabels will anchor itself at the bottom. This is assuming that you already adjusted the size of the UITableViewCell to fit the entire controls. Otherwise, I think the best way to handle this is to recalculate the y coordinates of the labels.

I found it useful to add this sort of behavior as a category on UIView so a view can resize one of its subviews to fit some arbitrary text, and optionally resize the parent view to fit the newly enlarged subview as needed.
http://blog.carbonfive.com/2009/07/10/resizing-uilabel-to-fit-text/

Related

Dynamically set UIScrollView height and UITableView Height depending on content

Setup: I have a scrollview with a label, uiimage, and a tableview (grouped) nested within. The label, uiimage, and tableveiw are populated by a webservice. The last section in the grouped table view contains text that will never be the same and could be as long as 5 characters to 250+. Also, this view is pushed from a basic tableview (so it has a navigation bar. If that matters at all).
Expected: The tableview should extend in height depending on the length of the content received from the web service. Then set the scrollview height to accommodate the height of the tableview
Problem: I'm not quite sure how to approach the issue. I really only know how to change the height to fixed values, which will not work properly in many scenarios.
The width and height of the cell are ignored; the cell cell is re-sized according to the value you return from -tableView:heightForRowAtIndexPath: or (failing that) tableView.rowHeight. It might appear as if the cell is big enough if the label in the cell is sized to be big enough, because the label is allowed to be bigger than (and render outside) the cell.
One way is to override -tableView:heightForRowAtIndexPath: to return the correct height. This isn't really the intended use of UITableView (it's primarily designed for lots of rows of a single height, dynamically generated from a list of content).
Another way is to set tableView.tableFooterView = myCustomFooter instead. This is probably the easiest way. Size it correctly before performing the assignment (the height matters; the table view will set the width for you anyway). Also make sure that the autoresizing flags are not set, or the size will appear to randomly change when the table view changes size (e.g. on autorotation).
I'd just focus on the variable height element, figure out the height that fits the text there. To figure out the height that a string will take when rendered use a snippet like this:
CGFloat MY_TABLECELL_WIDTH = 320;
CGFloat MY_MAX_HEIGHT = 10000;
UIFont *MY_FONT = nil; // load the correct font here.
CGSize maxSize = CGSizeMake(MY_TABLECELL_WIDTH,MY_MAX_HEIGHT);
CGSize textSize = [serverString sizeWithFont:MY_FONT
constrainedToSize:maxSize
lineBreakMode:UILineBreakModeWordWrap];

iphone code for auto uiLabel & uiTableViewCell resizing when font changed?

Can someone summarise the key pieces of objective-c code that would assist in solving this.
Objective - Autoresize a UITableView after a user changes the font size. Therefore if the user increases or descreases font both the (a) uiLabel heights should change to ensure they nicely include text, and (b) uiTableViewCell heights should also adjust.
Assumption is that:
UITableView has been extended via
creation of a custom cell view -
i.e. create a new view in a NIB that
forms for the content view of the
UITableView cells
each custom
cell has four UILabel's which form a
2 x 2 patter of UILabels - i.e. two
on top line and two on bottom line
so as the user increases the font
the horizontal spacing of the
UILabels would remain the same,
however the label heights would
change
So I assume the challenge / questions I have would include (and hopefully be answered by some sample code that someone can post)
Is it OK that the starting point here is an already laid out custom UITableViewCell in InterfaceBuilder? (or does the solution require it is constructed totally programmatically)?
How to calculate the heights the label's should be? Is this just with the NSString method "sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:", and do I need to add addition for margins etc?
How programmatically to increase the height of the labels dynamically - in which method do you do this & how to change the height itself
How to ensure that when UILabel at the top is expanded & grows, that it automatically pushes down the UILabel on the 2nd row? Does this happen by default or is there a specific property/setting you have to you to ensure this hapens.
How to then automatically increase the height of the TableViewcell, after the above has occurred. Which method to do this in, and how programmatically to perform the increase & redraw.
Hope this makes sense.
thanks
You can base on the XIB file as a default layout, then adjust the position/size later during runtime.
Yes use that method to calculate the required height. You need to add margins between labels yourself.
Change the label's frame.
You need to calculate the x,y of the 2nd row's label base on the x,y,height from the 1st row's label + margin.
hook with the following method and return the new height:
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
To get the UILabel's height to match your target font, you use the sizeWithFont function of NSString.
NSString *myText = #"Go Hokies";
UIFont *myFont = [UIFont boldSystemFontOfSize:15];
CGFloat lineHeight = [myText sizeWithFont:myFont].height;
The problem you may run into is if the text doesn't fit horizontally in the bounds you've defined. If you want the font to downsize accordingly, turn on the adjustment flag and set a min like this.
myUILabel.minimumFontSize = 10;
myUILabel.adjustsFontSizeToFitWidth = YES;

Adjusting the width of a UILabel in UITableViewCell based on the width of a second UIView in the Cell

I have a UITableViewCell with two subviews, a UILabel on the left, and a random input control on the right. The random input control on the right can vary in size, as can the length of the text, but since I can set the word wrap of the text on the left, I need to be able to adjust the size of the UILabel based on the width of the random input control. To complicate matters, the app needs to work in both portrait and landscape modes, which give the table cells different widths.
This wouldn't be difficult if I could read the width of the table cells and set the widths of its subviews appropriately, but at creation time the width of the cell is 0.
Any ideas?
Nothing easier than that: every UITableViewCell is also a UIView, which has a method designed for just that: layoutSubviews, which is called whenever the view (here: cell) needs a re-layout. This is where you lay out the content.

Programmatically determining padding for grouped UITableView

Is there a way to programmatically get a UITableView's 'grouped' style padding?
I'd like to size some things in my screen but I need to know how far left or right to place them on a grouped UITableView's UITableViewCell.
Since you are using the grouped style for your table view, you should be able to use the rectForSection: method to get the CGRect where that section will be drawn. You may have to already have added your cells to your view, however.
CGRect sectionRect = [tableView rectForSection:0];
int paddingLeft = sectionRect.origin.x;
As I see it, 'grouped' style padding == the origin of cell.contentView. but the value is assigned by table view only in tableView:willDisplayCell:forRowAtIndexPath: and is equal to 10 on iPhone/iPod Touch. querying it in cellForRowAtIndexPath: results in 0.

UITableView Did Load (Done drawing the cells)

Question
How can you detect when the Table View is done drawing the cells?
Issue
I got two labels within the contentView of an UITableViewCell. The size of these labels are dynamic. I was able to do so by subclassing UITableViewCell, in the drawRect method I adjust the frames of the two labels depending on their content. Now I want to align all the second labels.
My Thoughts in Steps
Determine the content in the table view and let it load automatically.
Run through the table view cells and determine the x position of the second label within the UITableViewCell that is the furtherest away.
Store this x position and when any cell is drawn use this x position to place the second label.
The problem is that if I use the following code:
for (int row = 0; row < [self.tableView numberOfRowsInSection:section]; row++) {
UITableViewCustomCell *cell = (UITableViewCustomCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:0]];
NSLog ([cell.labelTwo description]);
}
The second label has not yet been drawn, meaning I can't determine the size of the frame and thus can not find the proper x position to align all second labels.
I have tried subclassing the UITableViewController and looking at events such as viewDidLoad and viewDidAppear unfortunatly also in these events the cells aren't drawn yet.
What I Want ...
What I want is for the table view to draw the cells at least once so I can determine the sizes of the labels within the table view cell. I thought to accomplish this by looping through all the cells with cellForRow, but although it successfully returns the cell the content is not drawn yet meaning the frame remains with a width of zero.
Does anyone have a solution?
Thanks in advance,
Mark
Try calling sizeWithFont: on the contents of these labels to get the max width before you draw anything. You should be able to use it later in your cellForRowAtIndexPath: to adjust the width as you need.
I would recommend you reconsider using UITableViewCellStyleValue2 cells instead and attempt to configure the textLabel and detailTextLabel. I had a similar situation and this is how I did it.
First off, you really ought to just pick an explicit, fixed position at which the first label ends and the second one begins, based on what you know about the minimum and maximum lengths of the text that will be put in those labels. That would eliminate this problem entirely.
But if you want a solution: use the sizeWithFont: method or one of its cousins (see the Xcode docs). Specifically, loop through the values that will go in the first labels, apply sizeWithFont to each, and keep track of the largest width you see. (I'm assuming you have access to the values before they go in the cells; since they're dynamic, they must be passing through the table view controller, no?)
Now you have the value you seek, without having to perform the extremely wasteful operation of creating a bunch of cell objects and never using them for their intended purpose.
I think what you need to do is to add a viewController to the have the UITableViewController control the UITableViewCell itself so that you can capture the events of the labels loading. The viewController will have references to both labels so it can adjust them accordingly in response to -viewDidAppear.
I've never done this but a UITableViewCell is a view like any other so you should be able to set up a controller for it. You might need to manually activate the controller since you have no navigation controller to do it for you in this context.