UILabel animated resize side effect - iphone

I came across issue where I need to animate height change of UILabel frame or its enclosing view's frame. Label is multiline.
The issue is that given with large text which does not fit initially into label(say it takes 3 lines), then animating the label's height to increase, immediately changing 3 line to 4 and then animating the frame increase.
Opposite effect is when the text fully fit into label(4 lines), then I animate height decrease, 4 lines are instantly becoming 3 and only then I see animating frame size decrease.
This is of course not good for an eye.
What I expect is something like keep the label's origin.y intact and then as frame is increasing the more text is revealing from the bottom. The ellipsis may convert to missing word instantly, that is not a problem.

If you want to keep origin.y intact then you have to animate it with CoreAnimation stuff.
Set once:
label.layer.anchorPoint = CGPointMake(0,0); //I believe 0,0 is the upper left or it was 0,1?
after doing this you just need to change the size accordinly:
I would measure the text first (With NSString's methods)and see if the label needs to be resized.
In case it needs to then adjust label.numberOfLines and label.layer.bounds = CGRectMake(label.layer.bounds.origin.x,label.layer.bounds.origin.y,
label.layer.size.width, newHeight);
This should work
I hope this helps.

Related

UILabel Minimum Number Of Lines

If you take a close look an an iMessage conversation cell, you’ll notice that the preview text is always two lines long. This can’t be a hard coded row height because the rows adjust to dynamic type. How can you always force a label to take up a certain number of lines even if there isn’t enough text to do so?
Set the label's numberOfLines to 2 and end the label's text with a linefeed \n. Set the wrapping to word wrap to prevent the ellipses from appearing.
This guarantees that the label text consists of at least 2 lines worth of material. Thus it can never be less than 2 lines, and since the maximum number of lines is 2, it can never be more than 2 lines. Thus it will always be (wait for it) 2 lines.
One way I think this could be possible is having a UIView as a parent of the UILabel.
Fix the height of the UIView based on device size class. Let's say for example 50 points for Width = Compact and Height = Regular.
Embed UILabel in UIView
Set number of Lines = 0 for UILabel
Now match UILabel leading , trailing ,top edge with the superview and leave the height as it is , also don't set the bottom constraints.
Select the superview i.e the UIView and UILabel together and select Equal Heights.
Open the constraint window and change label height less than or equal to SuperView height.
Short Message
Long Message
Height Constraint of the UILabel with respect to SuperView.

UILabel not wrapping correctly after text change

I'm working via the IB and have a UILabel that's stretched almost to the end of the layout. I have it set with Lines=2, because the max amount of lines it should take is 2. However if it's only 1 line long, I would like it to have a vertical justification of top.
Label settings in IB:
Lines:2
Line breaks: Word wrap
In code, in the viewDidLoad method I set the text of the UILabel. However as part of the functionality at a point the text must change. This is my code:
[_main_lbl1 setText:[myUI MAIN_TITLE]]; //Always only 1 line
[_main_lblsub1 setText:[myUI SUB_TITLE]]; //May be 1 or 2 lines
[_main_lblsub1 sizeToFit]; //Causes vertical alignment (I believe)
Whenever I change the text and rerun sizeToFit, the text wrapping becomes totally messed up. Instead of reaching almost the end of the UILabel as set up in the IB, in some cases the text will wrap at little more than half the distance, in some cases it doesn't wrap at all.
Image of layout in IB:
Image of resulting label in simulator:
In the first label it seems to be working ok, the second label doesn't wrap at all.
Is there anything I have to do to keep the text wrapping when changing the UILabel text? Anything else I'm missing?
Note: Updated question to include more detail and pics.
Thanks
The issue is that you're using sizeToFit. Which stretches the label out to fit the text. If you need to change the size you can use:
CGSize maxSize = CGSizeMake(320, 9999); // 999 means it can be as tall as you like
CGSize textSize = [label.text sizeWithFont:label.font
constrainedToSize:maxSize];
label.size = textSize;
You shouldn't have to do anything special. It will automatically wrap the text to fit when you change it. Otherwise the text would run out of the text labels bounds (which is not what you want). Your problem is that sizeToFit permanently changes the frame of the label. It makes it as small as possible while still showing the text. You are having it resize its frame to the original text and then you are changing the text so it is no longer sized properly. You should reset the frame back to it's original, change the text, and finally call size to fit again.
In viewDidLoad:
self.originalFrame = self.mainLabelSub1.frame;
Then in viewWillAppear:
self.mainLabel1.frame = self.originalFrame;
self.mainLabel1.text = #"New Text";
Note:
A good way to see the borders of the text label to get an idea for the wrapping potential is to temporary set the background of the label to something like magentaColor that stands out.

Increase UIView's frame size at the left edge

I have an UIView that can grow dynamically in width. The view also have subviews located inside it's bounds.
Default behavior seems to be that when the view's frame grows along the x axis, increasing frame.size.width, it always grows at the right edge, keeping the subviews fixed as if there were a fix left margin. However, when I want to expand the view on the left edge this doesn't work because of this behavior. In this case I want it to behave in a mirrored way, as if there were a fix right margin. I could of course "manually" move all subviews so it looks like that is the case, but that seems really awkward since there could be plenty of them.
So I guess the question really is if there is a way to shift a views bounds relative to it's subviews? Is maybe autoresizingMask the way to do this?
Thanks.
Maybe you should take a look at the AutoresizingMask property of a UIView subclass :-)
For example, if you have a UILabel called labelVideoTitle, you could set a mask like this :
[ labelVideoTitle setAutoresizingMask:UIViewAutoresizingFlexibleWidth ];
You can by the way add 2 mask at once like :
[ labelVideoTitle setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight ];
Good Luck !
Edit : To increase the parent view frame size at the left edge, you could change too its X position to the left to give the impression wanted ^^ For example if you add 10 pt to the width, try modifying the X origin -10 pt :-)
In interface builder, you can graphically indicate in the CMD-3 (little ruler icon) Size Inspector what each element in your view should do when the parent view is resized: you can indicate which borders (top, left, right, bottom), the given element should "stick to" when the parent view is resized. You can also indicate whether the given element should itself resize (in either width or height) or stay the same size. Underneath the hood, this sets the autoresize mask for the UIView element you're editing, but especially for making an element stick to a particular border, Interface Builder is the way to go.
IB Size Inspector also has a neat little animation that shows you the effect on a hypothetical element (little red square) during a resize, given your settings to the left.

StretchableImageWithLeftCapWidth stretching wrong portions

I am trying to use a UIImage with stretchableImageWithLeftCapWidth to set the image in my UIImageView but am encountering a strange scaling bug. Basically picture my image as an oval that is 31 pixels wide. The left and right 15 pixels are the caps and the middle single pixel is the scaled portion.
This works fine if I set the left cap to 15. However, if I set it to, say, 4. I would expect to get a 'center' portion that is a bit curved as it spans the center while the ends are a little pinched.
What I get is the left cap seemingly correct, followed by a long middle portion that is as if I scaled the single pixel at pixel 5, then a portion at the right of the image where it expands and closes over a width about twice the width of the original image. The resulting image is like a thermometer bulb.
Has anyone seen odd behavior like this and might know what's going on?
Your observation is correct, Joey. StretchableImageWithLeftCapWidth does NOT expand the whole center of the image as you would expect. It only expands the pixel column just right of the left cap and the pixel row just below the top cap!
Use UIView's contentStretch property instead, and your problem will be solved. Another advantage to this is that contentStretch can also shrink a graphic properly, whereas stretchableImageWithLeftCapWidth only works when making the graphic larger.
Not sure if I got you right, but LeftCapWidth etc is made for rounded corners, with everything in the rectangle within the rounding radius is stretched to fit the space between the 'caps' on the destination button or such.
So if your oval is taller or wider than 4 x 2 = 8, whatever is in the middle rectangle will be stretched. And yours is, so it would at least look at bit ugly! But if it's not even symmetrical, something has affected the stretch. Maybe something to do with origin or frame, or when it's set, or maybe it's set twice, or you have two different stretched images on top of each other giving the thermometer look.
I once created two identical buttons in the same place, using the same retained object - of course throwing away the previous button. Then I wondered why the heck the button didn't disappear when I set alpha to 0... But it did, it's just that there was a 'dead' identical button beneath it :)

How to fit a String into a rectangle?

I have an NSString and want to fit it into a rectangle. The rectangle has a specified size, lets say width=150 and height=30. When the String is short and has only one character, it can be as high as the rectangle. More specific: It can have a big font size. But if the string has too much characters and would exceed the bounds of the rectangle, it must become smaller. More specific: It's font size must become smaller, so that it won't exceed the bounds of the rectangle. Is there a way of doing that without messing around in core graphics?
For some reason, UILabel's adjustsFontSizeToFitWidth Property has no effect. The text keeps beeing small even if there is plently of space.
I've set that to
label.adjustsFontSizeToFitWidth = YES;
but nothing happens. I hope there is another way to do that...
There are several part to UILabel that make this possible, but first you have to know if you want to truncate the string or make the font size smaller to fit in the rectangle.
For both cases you'll want to set the UILabel's numberOfLines property to 0, allowing the label to wrap as much as necessary. Then you'll want to set the frame of the UILabel to match the rectangle you're looking to fit. From there you take one of two paths:
Truncation: Set the lineBreakMode property to UILineBreakModeClip, UILineBreakModeHeadTruncation, UILineBreakModeTailTruncation, or UILineBreakModeMiddleTruncation depending on the truncation behavior you're looking for.
Resizing: Set the lineBreakMode to either UILineBreakModeWordWrap or `UILineBreakModeCharacterWrap' depending on your preference. Then you'll need to enter a loop to figure out the right font size. Start with a reasonable font size (e.g., 12) and:
Set the font property of the UILabel with a UIFont that matches that size
Call - (void) sizeToFit for the UILabel.
Check the frame for the UILabel:
If the frame will fit within the bounds you need it to, you're done
If the frame is still to big, drop the size of the font and repeat the loop
For the latter option you'll want to make sure you're not squeezing the text into oblivion, so you'll want to put a minimum size cap on the font size.
You can get more information from the UILabel and UIFont documentation.
adjustsFontSizeToFitWidth adjusts the font size down, not up.
Set the font on your UILabel to an appropriately large size, and UILabel will shrink it when necessary to fit in its bounds.
Set label font size to desired normal size.
Set label minimum font size to
smallest possible font
(minimumFontSize property)
Set adjustsFontSizeToFitWidth to
YES.
If you need multiple lines, set lineCount to 0 as the other poster noted.