Dynamic UILabel truncating the text - ios

I'm using code provided in this answer to create a dynamic label and it works for the most part. But whenever the label text goes over 94 characters in length it gets truncated and ellipsis' are added.
There is one more odd thing about this is that if I add more characters to the string they are shown but the last 2 lines are still truncated.
Eg.
The string:
this is a very very long string
with lots of words to test the
dynamic bubble sizing one two three.
shows up like this:
this is a very very long string
with lots of words to test the
dynamic bubble sizing one tw...
But when I double the string by using the same sentence again in the label it show more of te text but still truncates it.
Eg.
The string:
this is a very very long string
with lots of words to test the
dynamic bubble sizing one two
three. this is a very very long
string with lots of words to test
the dynamic bubble sizing one
two three.
shows like this:
this is a very very long string
with lots of words to test the
dynamic bubble sizing one two
three. this is a very very long
string with lots of words to tes...
Here's the code I'm using.
NSString *temp = [NSString stringWithFormat:#"this is a very very long string with lots of words to test the dynamic bubble sizing one two three"];
captionLabel.text = temp;
//Calculate the expected size based on the font and linebreak mode of your label
CGSize maximumLabelSize = CGSizeMake(296,9999);
CGSize expectedLabelSize = [temp sizeWithFont:captionLabel.font
constrainedToSize:maximumLabelSize
lineBreakMode:captionLabel.lineBreakMode];
//adjust the label the the new height.
CGRect newFrame = captionLabel.frame;
newFrame.size.height = expectedLabelSize.height;
captionLabel.frame = newFrame;
Hope someone has an idea because this has me scratching my head.
EDIT
Using captionLabel.frame.size.width instead of hard-coded 296 fixed it, thanks to #troolee, if he/she chooses to create an answer I will mark it correct.

I was hoping #troolee would have made his comment an answer by now but since he hasn't I'm going to post the answer and mark it correct so I can close off this question.
Using captionLabel.frame.size.width instead of hard-coded 296 fixed it.

Instead of captionLabel.lineBreakMode , just write UILineBreakModeWordWrap. It should work.

Try the following UILabel Category. Thanks for the creator.
UILabel+VAlign.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface UILabel (VAlign)
- (void) setVerticalAlignmentTopConstrainedToSize:(CGSize)size;
#end
UILabel+VAlign.h
#import "UILabel+VAlign.h"
#implementation UILabel (VAlign)
- (void) setVerticalAlignmentTopConstrainedToSize:(CGSize)size
{
CGSize textSize = [self.text sizeWithFont:self.font
constrainedToSize:size
lineBreakMode:self.lineBreakMode];
CGRect textRect = CGRectMake(self.frame.origin.x,
self.frame.origin.y,
self.frame.size.width,
textSize.height);
[self setFrame:textRect];
[self setNeedsDisplay];
}
#end

Related

Estimate character count in uitextview of non scrollable fixed size iOS

I have a scenario , where I want to calculate , How many characters can be placed within Non scrollable UITextView.
I have tried the following ,
Get the height of the Text that needs to be placed within UITextView
by the following code ,
CGRect rect = [labelStr boundingRectWithSize:CGSizeMake(label.frame.size.width, MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributes
context:nil];
labelHeight = rect.size.height;
and also computed the height of my UITextView.
But still with these two height values , I cant figure out the way to find out the character count within my UITextView.
Any Ideas will be greatly appreciated....
Thanks in advance.
Though not very glamorous, you could just type characters to fill the UITextView in the simulator and add a button that would count them for you, a simple method like this perhaps:
- (NSUInteger)numberOfCharactersInString:(NSString *)textToCheck // uitextview.text
{
NSUInteger *numOfChars = [textToCheck length];
return numOfChars;
}
Then you'll know how many characters can fill the UITextView. But, this wouldn't be a very useful method if you're using preferred fonts that change when the user changes the Text Size in Settings.

Localized UILabel with background

I have an app in two languages (English and German) and app contains labels with background. In English everything is ok but in German UILabels are to short and text which is in it is shorter with 3 dots. Like:
Can I add some auto-resize property which resize label to correct size? Last one thing is that I have a lot of labels interface-only. I want to save some time and figure it out in interface. Is it possible or the only way is set sizeToFit to labels? Thank you for advices.
So what you want to do is, set the sizeToFit in the interface.
It is quite easily possible.
Set the AutoShrink Property in Attributes inspector, and it will be equivalent to size to fit.
Further you can even Specify the minimum font size and font scale.
Kakshil's answer will work for the case that you're not wanting to resize the label to actually fit the contained text. It's going to reduce the point size of the text in an attempt to fit the available space. For truly dynamic text that may be the best option.
On the other hand, if you're wanting to actually resize the label to fit the text then you can call [label sizeToFit] after you change the label text. Alternatively, you can use sizeThatFits: to use a modified bounds, where you don't want the label to grow too big or too small.
I customised my label, add localization and set frame with inset. How's simple. But one disadvantage is that I have to set tag as key. My solution is:
- (void)layoutSubviews {
NSString *key = [NSString stringWithFormat:#"%d", self.tag];
self.text = NSLocalizedString(key, nil);
CGSize textSize = [self.text sizeWithAttributes:#{NSFontAttributeName:self.font}];
CGFloat strikeWidth = textSize.width;
[self setFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y, strikeWidth + 20, self.frame.size.height)];
[super layoutSubviews];
}
- (void)drawTextInRect:(CGRect)rect {
UIEdgeInsets insets = {0, 5, 0, 5};
[super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}

Display various size of text block in Xcode

I'm creating a questionnaire app. In the view controller, I have a question displayed as a label and then I have three answers below displayed as labels too. The problem is that if the question has multiple lines, it's being displayed in one line anyway, and if I stretch out the label, it overlaps with the answers.
What is the right way to display the question so that the answers appear just under the question, no matter how long the question is?
Try setting the property numberOfLines to 0 for your question label, it will allow an unlimited number of lines to be displayed. Then calculate the text size using iOS 7 method boundingRectWithSize:options:context::
CGRect questionFrame = self.questionLabel.frame
CGFloat maxWidth = questionFrame.size.width;
NSString *questionText = [NSString stringWithString:#"lorem ipsum"]; // your text
UIFont *font = self.questionLabel.font; // your label font
// Temporary attributed string
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:questionText attributes:#{ NSFontAttributeName: font }];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){ maxWidth, CGFLOAT_MAX }
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
// Assign the new height
questionFrame.size.height = rect.size.height;
self.questionLabel.frame = questionFrame;
Then move your answers label one by one under the question label:
CGRect answerFrame = self.answerLabel1.frame;
answerFrame.origin.y = questionFrame.origin.y + questionFrame.size.height;
self.answerLabel1.frame = answerFrame;
answerFrame.origin.y = answerFrame.origin.y + answerFrame.size.height;
self.answerLabel2.frame = answerFrame;
answerFrame.origin.y = answerFrame.origin.y + answerFrame.size.height;
self.answerLabel3.frame = answerFrame;
If you want to use UILabel you must first of all set its "numberOfLines" property to 0. The value "0" means "no limit", so the text will be broken in the right number of lines. Then you have the problem of determining the right size of the label, as the height changes depending on the length of the question. In such case you can use the function - (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context (available with iOS7 and that replaces the - (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode available before iOS7).
Once you determine the height of the label you change its frame accordingly. Obviously you must change the origin of the answers labels to avoid that they conflict with the question label.
Note that if both questions and answers are too long, you may end up with an overall labels height taller than the screen height. In such case you should put all these labels inside a scrollview or as cells of a table view, to allow scrolling.

Set UILabel Align top is not working in the cell

I have a problem to implement the text vertical alignment inside a table cell.
What I want to do is based on the length of the text I want to display a message top aligned in side one UILabel inside a cell.
For example if the message is only one line
The text should align top:
And if there are two rows then it should look like this:
At the beginning what I can see is like this
So I have searched the web and what I found is to
use the
[label1 sizeToFit];
But the problem with that is within the table view cell it is not always necessarily called especially when I switched to and from another tab view.
Then I tried to generate the label on the fly by code, but the problem is that let alone the complicated process of setting up the font format I want. I have to manage whether the label has been inserted or not then reuse it every time cellForRowAtIndexpath is called.
And more weirdly, once I select the row. The alignment is switched from the one you see in the first picture to the third one. It also happens when I switched to a different tab view and switch back to the view.
I was wondering if anybody has encountered such issue and have a solution to the problem.
Thank you for your reply in advance.
Edit:
#βḧäṙℊặṿῗ, what you said I have tried. It successfully align the label text if there is only one line. My situation is that, since I have multiple tab views. Once I switch back and forth between tabs view. The alignment just restored to centre-vertical alignment again. It also happens when I selected the row. Any idea?
Try this
// label will use the number of lines as per content
[myLabel setNumberOfLines:0]; // VERY IMP
[myLabel sizeToFit];
EDIT:
As you have one extra condition that maximumly display two lines then you need to set setNumberOfLines: to 2
[myLabel setNumberOfLines:2];
Create UILabel+Extras and add following methods to this class.
- (void)alignTop{
CGSize fontSize = [self.text sizeWithAttributes:#{NSFontAttributeName:self.font}];
double finalHeight = fontSize.height * self.numberOfLines;
double finalWidth = self.frame.size.width; //expected width of label
CGRect rect = [self.text boundingRectWithSize:CGSizeMake(finalWidth, finalHeight) options:NSStringDrawingTruncatesLastVisibleLine attributes:#{NSFontAttributeName:self.font} context:nil];
CGSize theStringSize = rect.size;
int newLinesToPad = (finalHeight - theStringSize.height) / fontSize.height;
for(int i=0; i< newLinesToPad; i++)
self.text = [self.text stringByAppendingString:#" \n"];
}
Call this method like this..
[YOUR_LABEL alignTop];
Either You set no of Lines to be 0 like
[yourLabelObject setNumberOfLines:0];
[yourLabelObject sizeToFit];
Or
You can find the height of label at run time depending upon textString length.
Following method will return you the size(height & width) of label for length of text string.
here width is fixed and only height will change :
- (CGSize) calculateLabelHeightWith:(CGFloat)width text:(NSString*)textString andFont:(UIFont *)txtFont
{
CGSize maximumSize = CGSizeMake(width, 9999);
CGSize size = [textString sizeWithFont:txtFont
constrainedToSize:maximumSize
lineBreakMode:UILineBreakModeWordWrap];
return size;
}
Yo need to calculate frame of label each time when u r doing to set text and set frame of label
I hope this will helps you.
Might sound a bit silly but this is my approach: For any field that needs to be top aligned I fill the text up with multiple "\n"s. This causes the text to be automatically top aligned. Pretty much the same as Mehul's method above.
http://i.stack.imgur.com/8u5q4.png

iOS: sizeWithFont for single character is different than in a string?

I am trying to determine the precise position of a character in a UILabel, say:
(UILabel *)label.text = #"Hello!";
I'd like to determine the position of the 'o'. I thought that I could just sum the widths of all the preceding characters (or the whole preceding string) using sizeWithFont. The width value I get though is bigger by about 10% than what it should be. Summing the widths of individual letters (i.e. [#"H" sizeWithFont...] + [#"e" sizeWithFont...] + l... + l...) accumulates more error than [#"Hell" sizeWithFont...].
Is there a way of accurately determining the position of a single glyph in a string?
Many thanks.
Yes, but not in a UILabel and not using sizeWithFont:.
I recently worked with Apple Developer Support, and apparently sizeWithFont: is actually an approximation. It becomes less accurate when your text (1) wraps across multiple lines and (2) contains non-latin characters (i.e. Chinese, Arabic), both of which cause line spacing changes not captured by sizeWithFont:. So, don't rely on this method if you want 100% accuracy.
Here are two things you can do:
(1) Instead of UILabel, use a non-editable UITextView. This will support the UITextInput protocol method firstRectForRange:, which you can use to get the rect of the character you need. You could use a method like this one:
- (CGRect)rectOfCharacterAtIndex:(NSUInteger)characterIndex inTextView:(UITextView *)textView
{
// set the beginning position to the index of the character
UITextPosition *beginningPosition = [textView positionFromPosition:textView.beginningOfDocument offset:characterIndex];
// set the end position to the index of the character plus 1
UITextPosition *endPosition = [textView positionFromPosition:beginningPosition offset:1];
// get the text range between these two positions
UITextRange *characterTextRange = [textView textRangeFromPosition:beginningPosition toPosition:endPosition]];
// get the rect of the character
CGRect rectOfCharacter = [textView firstRectForRange:characterTextRange];
// return the rect, converted from the text input view (unless you want it to be relative the text input view)
return [textView convertRect:rectOfCharacter fromView:textView.textInputView];
}
To use it, (assuming you have a UITextView called myTextView already on the screen), you would do this:
myTextView.text = #"Hello!";
CGRect rectOfOCharacter = [self rectOfCharacterAtIndex:4 inTextView:myTextView];
// do whatever you need with rectOfOCharacter
Only use this method for determining the rect for ONE character. The reason for this is that in the event of a line break, firstRectForRange: only returns the rect on the first line, before the break.
Also, consider adding the method above as a UITextView category if you're gong to be using it a lot. Don't forget to add error handling!
You can learn more about how firstRectForRange: works "under the hood" by reading the Text, Web, and Editing Programming Guide for iOS.
(2) Create your own UILabel by subclassing UIView and using Core Text to render the strings. Since you're doing the rendering, you'll be able to get the positions of characters. This approach is a lot of work, and only worthwhile if you really need it (I, of course, don't know the other needs of your app). If you aren't sure how this would work, I suggest using the first approach.
Well fonts are smart now a day and take in respect the position of a character to its pervious character.
Here is an example on how the starting position of the letter o:
NSRange posRange = [hello rangeOfString:#"o"];
NSString *substring = [hello substringToIndex:posRange.location];
CGSize size = [substring sizeWithFont:[UIFont systemFontOfSize:14.0f]];
No you can do the same for the string including the letter o and substract the size found in the string without the letter o.
THis should give the an nice start position of the letter and the size.
in ios6 you can do using attributed string
NSMutableAttributedString *titleText2 = [[NSMutableAttributedString alloc] initWithString:strHello];
NSRange posRange = [hello rangeOfString:#"o"];
[titleText2 addAttributes:[NSDictionary dictionaryWithObject:[UIFont systemFontOfSize:14.0f] forKey:NSFontAttributeName] range:NameRange];
and set your textView with this attributed string

Resources