Change the label width dynamically inside a UITableViewCell - ios

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.

Related

What makes UIView resized back to default when the UIScrollView containing it is scrolled?

I made a UIScrollView and it is scrolled horizontally.
Inside the UIScrollView, A UIView contains a UILabel to display a text and a UIButton to hide the view.
The width of the view changes as the text in label is changed by the user, while the button keeps its size.
What I want the UIView to do is to keep its size when the UIScrollView is scrolled to left and right. But the UIView goes back to its original size when scrolled.
The image below shows what the storyboard is set up; two rectangles are UIViews and UILabels in each have a text of "Label" by default. A letter X is a button. The horizontal area containing those two is UIScrollView.
The next one is the scene I run the app in simulator. I programmatically changed the borders of these UIViews. Those texts are selected from the menu I made, and the widths of UIViews are changed as the widths of UILabels change. Disregard why both labels have the same text; I didn't handled the second view. The case is the same even with only one UIView.
When I scroll the UIScrollView to right, the problem occurs. The widths of those UIViews go back to default as set in the storyboard.
Theh function below is called when the menu is selected. Sorry for these friggin weird variable names
//selectedTextPrim, selectedTextSecn: String()
//result1Text, result2Text: UILabel
//result1, result2: UIView
//result1XBtn, result2XBtn: UIButton
func processAddResult(){
result1Text.text = selectedTextPrim + " > " + selectedTextSecn
result1Text.sizeToFit()
result1.frame.size.width = result1Text.frame.size.width + 24
result1XBtn.frame.origin.x = result1Text.frame.maxX
result2.frame.origin.x = result1.frame.maxX + 8
result2Text.text = selectedTextPrim + " > " + selectedTextSecn
result2Text.sizeToFit()
result2.frame.size.width = result2Text.frame.size.width + 24
result2XBtn.frame.origin.x = result2Text.frame.maxX
// print("\(result1Text.frame.size.height)")
}
Does the code needs to be changed? Or is there any way to manage this by adding some code onto somewhere?
Your views are positioned by auto layout constraints. You can set the frame directly (as you are doing), but the next time the system performs a layout pass, auto layout will reset the frames according to the constraints.
Many things can trigger a layout pass. One of them is changing the bounds of a view. The way a scroll view scrolls is by changing its own bounds.origin. So every time the scroll view scrolls, it triggers a layout pass. During these layout passes, any change you made directly to a view's frame is reset to the frame dictated by auto layout constraints.
In this case, it looks like you want each label to automatically size itself to fit its text. Auto layout can do this automatically. If you don't put any other constraints on a label's size, auto layout will use the label's intrinsicContentSize, which the label sets automatically each time you set the label's text.
Then you want each background rectangle to automatically surround a label. You can do this by constraining the edges of the rectangle to the edges of the label (plus constants to provide padding). Then auto layout will automatically make the rectangle's frame follow the label's frame.
If you do it all correctly, the only thing you have to change in your code is the text of the labels. Auto layout will take care of resizing and repositioning the labels and the background rectangles.
You should watch “Taking Control of Auto Layout in Xcode 5” from WWDC 2013.

Autolayout - Make superview height equal to subview height + constant where subview is textView

I have a UIView and inside the UIView I have a UITextView. The UITextView does not scroll, instead I set it programmatically to its full height with the following line of code :
self.textView.sizeToFit()
Through the interface builder, I set the following constraints for the UITextView , including superView.bottom = textView.bottom + 25 :
But then this is the result that I get when I run the app :
If anybody has any idea how could I fix this to fit the whole 'extended' textView, that would be really appreciated if you could let me know.
Thanks in advance.
Use a label instead of a text view. The important difference is that a label has an intrinsic content size where as a text view doesn't (because it's intended to scroll its content). This allows the label to work with the constraint system to display all of the text (without you needing to calculate the size).
If you stay using the text view you should add a height constraint and calculate the required height and configure the constraint appropriately.

Get variable height for a UIButton for iPhones 5/6/6+

For my 1) portrait only 2) deployment target iOS7/iOS8 app, I have in my design UIButtons which have variable heights, for iPhone 5, iPhone 6 and iPhone 6+. I am trying to use auto layout for this. (Not using size classes though).
Using auto layout how can I specify variable height for UIButton for these 3 screen sizes. The buttons look fine on iPhones 5* models, but thinner on iphone 6/6+. Now in auto layout I can say height >= or = or <= say 55), but how do I specify 44 for iphone5, 55 for iphone6, 66 for iphone6+?
Is this something that I can achieve using only auto layout or do I need to manupulate (frames) it in code? What is the point of me using auto layout then?
In addition to frames my designs also specify different font sizes. How do I go about this. Any best known methods for this, Stack-O friends .. ??
You are correct to ask "what is the point of auto-layout if I have to manipulate frames directly"? Thankfully, you don't have to.
An easy way of doing it is specifying the height in relation to a view of standard height (think a view that fits the whole screen).
For example, we can set our button's height to equal half the height of the view.
This way, the button is always going to scale with the view, either upwards or downwards (size-wise). Auto-layout will guarantee that the relation between them will always be 1/2.
Now the button will be half the size of its superview, regardless of size.
It sounds like you need to be modifying the height constraints constant value.
In your xib/storyboard, create an outlet to your view/controller for the height constraint.
At runtime, probably in viewDidLoad, you will work out which device you're on, and then just change the constant of the height constraint.
CGFloat height;
// if iPhone 5
// height = 44
// else..........
self.buttonHeightConstraint.constant = height;
This will automatically trigger a flag that tells AutoLayout to recalculate frames and layout the view again.
I managed this by adding a Height-Constraint to the UIButton. Make an Outlet and you can set the Height in your UIViewController subclass with _myConstraint.constant = 55;

Fluid UI layout on iPhone

I have an Android app with a UI like this for viewing emails:
I'm trying to port this to iOS and need it to work with iOS 5.0 and above (so can't use auto-layout in iOS 6.0). Hopefully you can tell how the layout should adjust/flow based on the example.
What would be the best way to handle this type of layout? The From and Re lines need to be variable height as shown (actually the To: line as well). The message body needs to be variable height of course.
My only attempt so far has been trying to use UITableViewController with static cells. I am able to get the variable height that way, by using sizeWithFont inside heightForRowAtIndexPath, to return the required height for each row. Using that method I'm having a heck of a time trying to get the style I want (rounded corners and background only for the top part).
So is there a better way? Maybe something that uses Collection View or Container View? On some other screens I need to port I have similar issues, but they have more levels of nesting (rounded blue section inside a white section inside a rounded blue section). Or would I be better off not using IB and building the entire UI in code from just basic label elements and generic views?
The easiest way I can think of is to manually compute for the label frames inside viewDidLayoutSubviews. Here's some pseudo-code:
On creation:
In IB, put all labels as subviews of the blue area. Check that the autoresizing mask of the container sticks to the top, left, and right, as well as have stretchable width. We'll fix the height and the subview frames in code. The message body can be a label or a textview as a separate view.
In viewDidLoad, set the containing view's layer cornerRadius, borderColor, etc. as appropriate.
In viewDidLayoutSubviews:
Time label: Easy. Just set the width to the superview width minus some padding, set the height with sizeWithFont:
For To:, From:, and Re:; call sizeToFit. Get the max width and hold on to that.
To: label: Set the x to 0 and y to the time label's bottom.
Receiver's name label: Set x to the width you got from (2.) and y to same as (3.). Set width to (container width - (2.)) and height with sizeWithFont:.
Do the same steps from (3.) to (4.) for the From: and Re: rows.
Set the blue view height to the frame bottom of the subject label.
Fill the rest of the frame with the body textview/label.
You have to add paddings on your own because sizeToFit and sizeWithFont: won't do that for you. Also, the body UITextView can scroll on it's own, but if you are expecting long subject titles then you should wrap the whole thing in another UIScrollView (or in IB just set the main view's class to UIScrollView)

How to layout UITextview beneath other textview?

(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.

Resources