Calculation Frame of a UILabel Subclass - ios

The bottom line is that I'm trying to reproduce the UI that iMessage has.
For the Label:
The special padding of that type of text made me create a custom UILabel. Here's the code under drawTextInRect:
[super drawTextInRect:UIEdgeInsetsInsetRect(rect, UIEdgeInsetsMake(0, 15.0, 5.0, 15.0))];
No mystery for now.
The problem comes when my cell (that contain that label has to calculate height).
The Label gets a rounding effect on the label like so:
cell.message.layer.cornerRadius = 18;
[cell.message sizeToFit];
Apparently I can't get the proper height and width of that label. I'm using sizeToFit and then I mesure the possible sizes with "sizeWithFont:" (deprecated in iOS 7) and "boundingRectWithSize:".
The only way the text can show properly is adding manually an undetermined amount of size to height and width once the calculations are made.
The best I can get then is a screen that may look good but still has some problems and not draws properly the texts.
The link has a screen of some of the screens not showing properly.

The only answer I've been able to see looking at code from other people is that they at some point make their own calculations based on letter size.
Anyone with this problem check : https://github.com/jessesquires/MessagesTableViewController
It was the only source I could find, at the end for some cases the boundingRectWithSize is not good enough.

Related

Prevent UILabel from clipping it's text when the font size is larger than the label height

I have a circumstance in my app whereby a label may be given a font size greater than it's height. This is to do with some rather complex architecture and layout code. Normally I would increase the label's height to accommodate the larger font but that is profoundly difficult to do in my scenario and I would rather avoid it.
The next logical thing is to turn clipsToBounds off, to allow the text sublayer to overflow the bounds of the label. Unfortunately this seems to have no effect in this case as the text is still clipped.
Am I missing something?
Looking at the documentation for UILabel:
https://developer.apple.com/documentation/uikit/uilabel/1620545-textrect
I think you need to override the method textRect(forBounds:limitedToNumberOfLines:) by explicitly increasing the rectangle returned by this method to the containing size of the label’s string rather than the bounds of the label.
(This solution does of course require you to subclass.)
Hope that helps.
You should be able to get the font height from font.lineHeight and then reduce the font size until the line height is less than the label height.
The reason (need citation) is that UILabel which is embeeded in UIButton cares extra glyph information embedded in font whereas an independent UILabel doesn't.
Solution
You can nest a separate UILabel on top of your UIButton and it will solve the problem. It's ugly but it works. There are few workarounds that you ought to try.
Workarounds
Depending on the scenario here is a small checklist that I found as accepted answer or useful for someone.
1) If you're using a UIButton Make sure you're using this method
[button setTitle forState:]
otherwise you'd need to use the following code to refresh the state
[myButton setNeedsLayout];
2) You might need to adjust your font size to fit the width of the label.
[yourLabel setAdjustsFontSizeToFitWidth:YES];
3) Although setting clipToBounds works in consecutive hierarchy, You might want not want to set individually on either Button or Label.
[yourButton setClipsToBounds:NO];
[yourButton.titleLabel setClipToBounds:NO];
There are few solutions that are pointing UIButton subclassing method which are essentially trying to add UIEdgeInset to button.

Autoshrink in UILabel only for width?

I have some ASCII syntax diagrams which must not have line breaks in the middle.
These don't have to be editable so I thought the best way is to use an UILabel with auto shrink option. But this option shrinks the text also if the content doesn't fit the height of the labels frame rectangle.
I just want to shrink only if the content doesn't fit the width. It would be absolutely fine to scroll vertically through the text.
What is the best way to do this with UILabel or any other UI element?
Use UITextView with 'editable' property set to false.
So let me rephrase your question. I guess what you want is a UILabel which can show multiple lines, but the longest line need to fit into the width of UILabel. If this is what you want, well the imagination is weird to me...
But anyway, I feel there's a conflict in your settings. First, allowing multiple lines implies you set "Lines" attribute (number of lines) as 0, which allows unlimited lines. But then Autoshrink will play no effect. I'm afraid it is not possible to be done by just setting the storyboard and instead, you need to write some code.
I guess people have raised related questions earlier, by which they want to dynamically change the font size when the text become too long. I guess you want to take a look about this:
Autoshrink on a UILabel with multiple lines
The last issue is you also want the scrolling effect (this is why I feel the outlooking will be weird.) But in short, to achieve this you need 1) dynamically change the UILabel height, most likely using the same technique as explained in the reference thread, and 2) wrap the UILabel in a scroll view. Maybe this can achieve what you want.

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];

What is the most concise and semantic way to lay out a paragraph of text of variable length for IOS7?

As far as I know, laying out paragraphs can be done with:
a) UITextView
Resizing the textview to fit the content in didlayoutsubviews
Example here: Weird thing occurs when using sizetofit of a UITextView in IOS7
b) UILabel
Setting the Lines to 0, using sizetofit
Example here: Multiple lines of text in UILabel
However, I am unable to get either of these to work in IOS7 (having previously used them in ios6.x). There must be a definitive and clear way to just lay out a paragraph, its such a seemingly simple task.To be specific, this is just a paragraph of text that is:
non-editable
variable length
Works consistently whether using storyboards or code only
So please, what is the way to do this?
UITextView works fine on iOS 7. If you don't use Auto Layout, then calling sizeToFit on UITextView object should be enough. If you do use Auto Layout, then make a height constraint on UITextView object and set its constant in code in the following way:
CGSize sizeThatFits = [self.textView sizeThatFits:CGSizeMake(yourAvailableWidth, MAXFLOAT)];
self.textViewHeightConstraint.constant = ceilf(sizeThatFits.height);
I've seen some problems with UILabel recently, e.g. Lines missing from tall UILabel when embedding NSTextAttachment
With the UILabel, I was able to to get this working by:
setting the lines to 0
setting my line break mode to word wrap
ensuring that the height constraint is set to a "greater than or equal to"

How do I prevent text from being cut off like in UITextView?

I have a UILabel and a UITextView both with the same text (the string "SnellRoundhand", in Snell Roundhand Bold font, point size 21). The text in the UITextView appears correctly, but the UILabel has its text cut off on the left and right sides. How do I get the text in the label to appear properly?
Some notes:
Expanding the frame of the label won't work because it might solve the cutoff issue on the right side of the text but not on the left side.
I can't take the cheap way out and center the text; the text must stay at whatever alignment it is in right now.
The reason I can't just change everything to UITextViews is because my app does some processing in the background and it crashes whenever it instantiates a UITextView. I'm hoping I can get around the issue by using UILabel instead to render the text.
In iOS 6, a very nice new feature of UILabel is that it supports attributed strings. Attributed strings can include paragraph margins. So you can add margins to your string, thus ensuring that there will be some extra space between the edges of the label and the drawing of the string.
This section of my book has sample code that adds margins to a string drawn in a UILabel:
http://www.apeth.com/iOSBook/ch23.html#_attributed_strings
If you want to run on a system earlier than iOS 6, you can subclass UILabel to force the text to be drawn inset from the edges of the label, as shown in this code (also from my book):
- (void)drawTextInRect:(CGRect)rect {
[super drawTextInRect:CGRectInset(rect, 5.0, 5.0)];
}
I don't have a good answer, but I can suggest a kludge that sorta does what you want done and might give you some useful ideas. The problem sure seems to suggest a fundamental problem with Label and TextView handling for funky fonts.
The concept is simple enough:
Size the TextField with left (or right) justification to just fit the contents.
Slightly enlarge the text field width.
Change the justification to center.
This will result in a field just wide enough to display the text without clipping (if you enlarge it the right amount). I know you said you couldn't change the text alignment, but doing it this way only moves the text a point or two and it ends up where it needs to be to display the full text. The field ends up the size, and the text in the position it ought to be. For instance:
self.textField.textAlignment = NSTextAlignmentLeft;
[self.textField sizeToFit];
CGRect frame = self.textField.frame;
frame.size.width += 4;
self.textField.frame = frame;
self.textField.textAlignment = NSTextAlignmentCenter;
This works. If it isn't useful to you directly I hope it gives you some ideas.
Something I tried that wasn't helpful was subclassing UITextField and overriding the textRectForBounds: to enlarge the area used to draw the text. I could move the text starting position slightly to the right, but it still clipped the left edge. Turning off the clipsSubviews property didn't help. Seems like Apple's problem here.
On iOS 6 the UITextView has a margin on each side, you can adjust the content inset to prevent the text from using those margins.
[textView setContentInset:UIEdgeInsetsMake(-8, -8, -8, -8)];

Resources