How to layout UITextview beneath other textview? - ios

(iOS)
I have a view that contains multiple textviews under static headings (see image below). The text of the textviews will change dependent on the previous view. I am having trouble getting Heading 2 and its textview to layout beneath heading 1 and its text view (this is all contained within a scrollview). Any ideas on a good way to ensure that these textviews layout appropriately? I want the textviews to be able to wrap height, moving all views "below" it further down the view. (Note: I have tried, via google-fu, a number of different methods involving things along the lines of the following without much success:
CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;
_scrollView.contentSize = CGSizeMake(frame.size.width, 10+CGRectGetMaxY(frame));
)
Goal:
Bad Layout using above code:

Not much to go on, but it looks like you may not have "moved" the second label and text view down to compensate for the now larger upper text view. Try changing the frame of the lower label and text view so that the Y value places them down far enough to clear the upper text view.

Related

Why do my controls get squished inside a scroll view?

I'm building an iOS app and every time I use a scroll view and put other views and controls inside of it this happens:
How do I prevent this from happening? I tried putting the scroll view in a UIView and putting a UIView inside a scroll view and putting other controls inside of the nested views but the same thing still happens. Any ideas on how to fix this?
After you add something inside scrollView, it doesn't know what width and height it will have. Thus, it is unable to correctly display its subviews.
There are some major solutions:
You need to specify correct sizes AND distances both vertically and horizontally.
E.g. scrollView will have 1 label. Then you should specify something like this:
label 1:
leading = 20, trailing = 20, width = 100 (this will solve horizontal dimension)
top = 20, height = 100, bottom = 20 (this will solve vertical dimension)
Of course, labels are self-sizing. So if you specify the text/font/number of lines, you don't need to set fixed width and height.
You can add some view (if your layout allows that) which will take the whole width of the screen. In this case you set leading and trailing to 0, and instead of setting fixed width (which varies on different screen sizes), you need to center that view horizontally inside the scrollView.
This will solve the horizontal dimension.
Instead of using constraints use the autoresizing feature. The controls resize depending on the way they were placed on screen and what the settings on the Autoresizing is.
Autoresizing

Changing UITextView height depending of it text

i have app that have table with many cells, when user tap on it, then detail view controller appear. Detail View Controller have an image and UITextView, that is not editable and it purpose only for showing text (just like label). Text it contain come from an xml file, sometimes it have several rows, sometimes there is a lot of text.
What i want is - to make UITextView height change depending of amount of text it have. For example, for several rows it might be 50 pixels height, in other case 300 pixels. How could i measure correct height and set it for UITextView? Again i want to point that it purpose only for showing text, not edit in any way. My second task is to measure final UITextView height and store it in some variable.
And there is what i've tried:
CGRect textViewRect = self.myTextView.frame;
textViewRect.size.height = self.myTextView.contentSize.height;
self.myTextView.frame = textViewRect;
But apparently its not working. Any idea how to achieve that?
Any advice would be appreciated, thanks!
Use this method of UIView:
- (CGSize)sizeThatFits:(CGSize)size
Typically you want your view limited in width, but any height. So you pass in a size with width as much as you want, and height for example 10000.0, so it gets as high as it needs. This returns how big the view needs to be according to its current content.
Try this
UITextView *textview1;
[textview1.text sizeWithFont:text.font constrainedToSize:textview1.frame.size];

iOS reflow layout with UIButtons that change size

I am building an iOS app that uses a UILabel to present a question at the top of the screen and then displays a number of UIButtons with text in the titleLabel to get the answer. I am using this View to display many different questions at different times and each question and set of answers has a different number of words in it. As a result, each UIButton can end up with a very different number of words, which creates a layout problem. I am currently using some code like this:
self.firstAnswer.titleLabel.numberOfLines = 0;
self.firstAnswer.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.firstAnswer.titleLabel.textAlignment = NSTextAlignmentCenter;
[self.firstAnswer sizeToFit];
which allows the buttons to resize itself to keep all the text onscreen. It also, however, causes the uibuttons to overlap vertically when a button resizes too much vertically (ie, the titleLabel is now 4 lines instead of 1). Is there any way to cause a button that is vertically below another button that has resized itself to move down to make room for the newly resized button?
What if you update the position of the following buttons based on the new height of the firstAnswer:
self.secondItem.frame = CGRectMake(self.secondButton.frame.origin.x,
self.firstAnswer.frame.origin.y + self.firstAnswer.frame.size.height + 10,
self.secondButton.frame.size.width,
self.secondButton.frame.size.height);
If you've got multiple other items, you can reposition them after each subsequent one, or use a general offset for all.
EDIT:
If multiple buttons follow, you cold also just put them inside a single tranparent UIView, then just offset that UIView alone.
Yes, use auto layout and give the buttons vertical spacing constraints to their nearest top and bottom neighbors. This will keep the spacing the same no matter how many lines you need for the button.

Change the label width dynamically inside a UITableViewCell

I am trying to build up an custom table view.
As you can see in the picture, I set the width of the label by default as 160 point in side the story board and change the width on the fly when the table is loaded. I am implementing this by modifying "cellForRowAtIndexPath" delegate method.
So based on the length of the date, I am setting the width of Label1 to maximum utilise the real estate on the phone screen.
CGFloat timeStampWidth = [cell.timestamp.text sizeWithFont:cell.timestamp.font].width;
CGFloat ksCompanyNameLableMaxWidth = 235;
NSLog(#"timeStampWidth:%f", timeStampWidth);
CGSize companyNameLableSize = CGSizeMake((ksCompanyNameLableMaxWidth - timeStampWidth), cell.companyNameLabel.frame.size.height);
CGRect newFrame = cell.companyNameLabel.frame;
newFrame.size = companyNameLableSize;
cell.companyNameLabel.frame = newFrame;
But when I load the app, all the label1s are set as 160 point as set in the storyboard although by debugging I have seen my code get executed for each cell.
To my surprise, if I scroll down and scroll back up again. The block of code is getting called again and the label is set as I wish.
Moreover, if I switch between the tabs, the label is restored to the abnormal status again.
This sounds like a consequence of auto layout -- when using it, you shouldn't set frames at all, instead you should adjust the constraints. You can make an IBOutlet to the width constraint of your label, and adjust its constant value in code.
If you are using auto layout, you can just set the x and y position, and then nothing for the height and width, and the label will correctly size itself to fit its contents. One caveat if you are using Xibs or Storyboards, don't put any text in your label in the storyboard, or it will want to size to that text. So delete the placeholder text from the storyboard, set the constraints and then you will be good to go.
You can also create and position the UILabel programatically, this way the iOS auto-layout will not interfere with your frame change.

Where is this vertical spacing coming from in UILabelView?

I'm creating an iOS view that displays various static text elements. The xib looks like this:
It uses four labels for the title, timestamp, body, and footer. Every view is anchored to the sibling view above it vertically and anchored to the left/right of the parent view. All labels have a fixed height except the body which has a >= height and the number of lines set to 0 with "word wrap" as the line wrapping style. The parent view is a UIScrollView.
On the iPhone it looks like fine:
However on the iPad it looks like this:
Huh? Where is all that extra vertical space in the body label coming from? The xib and its view controller are identical between iPhone and iPad (there is no custom iPad code at the moment). I've found that the vertical space is directly related to how many line-wraps the label renders. If no lines wrap, no extra vertical space. If only a few lines wrap, there's a little extra vertical space. If nearly every line wraps, well, that's what it looks like.
First of all any ideas on why UILabel is behaving this way?
Second of all, if I can't make it stop doing this how can I work around it?
I've already tried a few things. If I call [bodyLabel sizeToFit] within -viewDidLayoutSubViews then it fixes the label but doesn't fix the layout of any of the sibling views (e.g. the Footer label is stuck way at the bottom of the screen instead of pulled up to just under the body). Any attempts to get the entire view to re-layout its children after calling sizeToFit is ignored. I've also tried sizing the UILabel by calculating height based on font, which results in the same behavior as -sizeToFit (albeit with more code).
Replacing the Body UILabel with a UITextView instead doesn't give me the weird vertical spacing issues but I need to calculate the height of the UITextView manually (using font calculations) and something about resizing the UITextView within the parent UIScrollView makes it so the UIScrollView simply refuses to scroll (as if it doesn't know its contents are too big for its bounds).
So at the moment I'm stuck. Even just an explanation of why UILabel behaves this way on the iPad layout would be helpful.
In case anyone else runs into this same issue using autolayout... I may have been able to solve the same issue by creating a constraint as Coche suggests, but I realized I had a preferredMaxLayoutWidth that was too small set on the uilabel. Once I set an accurate preferredMaxLayoutWidth (the actual width of the label) the spacing on top and bottom disappeared.
The main problem is that the method for auto resizing the text inside your Label is failing because in iPad your Label doesn't have a set width from the beginning, it is calculated on run time and that's the source of that mess. On iPhone, as your Label has a set width (on IB) there is no troubles.
There are two ways for solving the problem:
Having two storyboards : one for iPhone and one for iPad
Doing this will make that your Label knows its width since the beginning and it will just works as on iPhone.
Having just one Storyboard for both iPhone and iPad
You can go around the problem by calculating the size that best fits its text and with that result add a height constraint by code to the Label. For calculating the desiredSize you can calculate the width with this formula: Current View's width - (Leading space + Trailing Space). Here is my code
CGSize desiredSize = [_bodyLabel sizeThatFits:CGSizeMake(self.view.frame.size.width-40, 10)];
NSString *visualContraint = [NSString stringWithFormat:#"V:[_bodyLabel(%.0f)]",desiredSize.height];
[_bodyLabel addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:visualContraint
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:nil
views:NSDictionaryOfVariableBindings(_bodyLabel)]];
objective-c

Resources