How do I truncate a string within a string in a UILabel? - iphone

Say I have The Dark Knight Rises at 7:45pm and I need to fit that into a fixed-width UILabel (for iPhone). How would I make that truncate as "The Dark Knight Ris... at 7:45pm" rather than "The Dark Knight Rises at 7:4..."?

UILabel has this property:
#property(nonatomic) NSLineBreakMode lineBreakMode;
You enable that behaviour by setting it to NSLineBreakByTruncatingMiddle.
EDIT
I din't understand that you wanted to truncate only a part of the string.Then read this:
If you want to apply the line break mode to only a portion of the text, create a new attributed string with the desired style information and associate it with the label. If you are not using styled text, this property applies to the entire text string in the text property.
Example
So there is even a class for setting the paragraph style: NSParagraphStyle and it has also it's mutable version.
So let's say that you have a range where you want to apply that attribute:
NSRange range=NSMakeRange(i,j);
You have to create a NSMutableParagraphStyle object and set it's lineBreakMode to NSLineBreakByTruncatingMiddle.Notice that you may set also a lot of other parameters.So let's do that:
NSMutableParagraphStyle* style= [NSMutableParagraphStyle new];
style.lineBreakMode= NSLineBreakByTruncatingMiddle;
Then add that attribute for the attributedText of the label in that range.The attributedText property is a NSAttributedString, and not a NSMutableAttributedString, so you'll have to create a NSMutableAttributedString and assign it to that property:
NSMutableAttributedString* str=[[NSMutableAttributedString alloc]initWithString: self.label.text];
[str addAttribute: NSParagraphStyleAttributeName value: style range: range];
self.label.attributedText= str;
Notice that there are a lot of other properties for a NSAttributedString, check here.

You have to set the lineBreakMode. You can either do that from Interface Builder or programmatically as follows
label.lineBreakMode = NSLineBreakByTruncatingMiddle;
please note that since iOS 5 the type of such property changed from UILineBreakMode to NSLineBreakMode.

My first idea would be two labels side-by-side both with fixed width, but I'll assume you've ruled that out for some unstated reason. Alternatively, compute the truncation manually, like this ...
- (NSString *)truncatedStringFrom:(NSString *)string toFit:(UILabel *)label
atPixel:(CGFloat)pixel atPhrase:(NSString *)substring {
// truncate the part of string before substring until it fits pixel
// width in label
NSArray *components = [string componentsSeparatedByString:substring];
NSString *firstComponent = [components objectAtIndex:0];
CGSize size = [firstComponent sizeWithFont:label.font];
NSString *truncatedFirstComponent = firstComponent;
while (size.width > pixel) {
firstComponent = [firstComponent substringToIndex:[firstComponent length] - 1];
truncatedFirstComponent = [firstComponent stringByAppendingString:#"..."];
size = [truncatedFirstComponent sizeWithFont:label.font];
}
NSArray *newComponents = [NSArray arrayWithObjects:truncatedFirstComponent, [components lastObject], nil];
return [newComponents componentsJoinedByString:substring];
}
Call it like this:
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 160, 21)];
NSString *string = #"The Dark Knight Rises at 7:45pm";
NSString *substring = #"at";
CGFloat pix = 120.0;
NSString *result = [self truncatedStringFrom:string toFit:label atPixel:120.0 atPhrase:#"at"];
label.text = result;
This generates: #"The Dark Kni...at 7:45pm"

Related

How to set Line Spacing in UI Text View (Empty text view) to enter message with line space

In my app i need to set some line spacing on ui text view..
I know we can do it for non editable textviews / labels using paragraph style spacing
But in my app when i enter text it was not working,
I can do it only when i have a predefined text on it, if once i clear the text paragraph sty will not work
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.minimumLineHeight = 35.f;
paragraphStyle.maximumLineHeight = 35.f;
UIFont *font = [UIFont fontWithName:#"AmericanTypewriter" size:18.f];
NSString *string = #"This is a test";
NSDictionary *attributtes = #{
NSParagraphStyleAttributeName : paragraphStyle,
};
deedTextView.font = font;
deedTextView.attributedText = [[NSAttributedString alloc] initWithString:string
attributes:attributtes];
But, I dont have any pre defined text like NSString *string = #"This is a test";
Text view must be empty, while begin
I had the same Problem. Based on Sergius answer I came up with the following working solution.
The problem with Sergius answer was that all other already set attributes will be overwritten (Font, Color...)
So it is better to edit the existing typingAttributes:
NSDictionary* d = deedTextView.typingAttributes;
NSMutableDictionary* md = [NSMutableDictionary dictionaryWithDictionary:d];
[md setObject:paragraphStyle forKey:NSParagraphStyleAttributeName];
deedTextView.typingAttributes= md;
One simple option that comes to mind is the following.
Using one of those 2 methods from UITextViewDelegate you can achieve what you want:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
- (void)textViewDidChange:(UITextView *)textView;
You algorithm is the following - take the textView.text, convert it to the style of your needs and set textView.text as textView.attributedText
You can also try setting this:
deedTextView.typingAttributes = [NSDictionary dictionaryWithObject:paragraphStyle forKey:NSParagraphStyleAttributeName];

How to get the range where UILabel will truncate a text [duplicate]

This question already has answers here:
Get truncated text from UILabel
(3 answers)
Closed 9 years ago.
I'm trying to figure out a way to understand at which range an instance of UILabel will truncate a text. I know how to get the size that a string would occupy using the -sizeWithFont:constrainedToSize:lineBreakMode:.
Let's say that we have a UILabel of about 5 lines and a long text, using the method above I'm able to know if it will fit or not. If it doesn't fit I'd like to add another UILabel with the remaining text. I'm doing that because the view layout is mixed with an image and when the image finish I'd like to have a text along the whole width of the view.
I know that with core text I can do that in just one view, but I'd prefer to go easy with UILabel.
/*IMAGE*/##/*TEXT*/
/*IMAGE*/##/*TEXT*/
/*IMAGE*/##/*TEXT*/
/*IMAGE*/##/*TEXT*/
/*IMAGE*/##/*TEXT*/
/*****TEXT*************/
/******TEXT*************/
/******TEXT**************/
Well I've found a solution the answer is a duplicate Get truncated text from UILabel
I copy the modified method from that answer, you need to import CoreText framework and be sure that the label is set to word wrap:
- (NSArray *)truncate:(NSString *)text forLabel: (UILabel*) label
{
NSMutableArray *textChunks = [[NSMutableArray alloc] init];
NSString *chunk = [[NSString alloc] init];
NSMutableAttributedString *attrString = nil;
UIFont *uiFont = label.font;
CTFontRef ctFont = CTFontCreateWithName((__bridge CFStringRef)uiFont.fontName, uiFont.pointSize, NULL);
NSDictionary *attr = [NSDictionary dictionaryWithObject:(__bridge id)ctFont forKey:(id)kCTFontAttributeName];
attrString = [[NSMutableAttributedString alloc] initWithString:text attributes:attr];
CTFramesetterRef frameSetter;
CFRange fitRange;
while (attrString.length>0) {
frameSetter = CTFramesetterCreateWithAttributedString ((__bridge CFAttributedStringRef) attrString);
CTFramesetterSuggestFrameSizeWithConstraints(frameSetter, CFRangeMake(0,0), NULL, CGSizeMake(label.bounds.size.width, label.bounds.size.height), &fitRange);
CFRelease(frameSetter);
chunk = [[attrString attributedSubstringFromRange:NSMakeRange(0, fitRange.length)] string];
[textChunks addObject:chunk];
[attrString setAttributedString: [attrString attributedSubstringFromRange:NSMakeRange(fitRange.length, attrString.string.length-fitRange.length)]];
}
return textChunks;
}

Is it possible to highlight a NSString or draw some color to a string

i am having this code to get the text between "." for example i am having lots of text like .1 this is first.2 this is second.3 this is fourth etc etc.when i tap the first ext it displays the first text in log .the code is
- (void)textViewDidBeginEditing:(UITextView *)textView
{
[NSTimer scheduledTimerWithTimeInterval:0.001 target:maintextview selector:#selector(resignFirstResponder) userInfo:nil repeats:NO];
}
- (void)textViewDidEndEditing:(UITextView *)textView
{
NSRange selectedRange = [textView selectedRange];
NSString *backString = [maintextview.text substringToIndex:selectedRange.location];
NSRange backRange = [backString rangeOfString:#"." options:NSBackwardsSearch];
NSRange backRangee = [backString rangeOfString:#"." options:NSBackwardsSearch];
int myRangeLenght = backRangee.location - backRange.location;
NSRange myStringRange = NSMakeRange (backRange.location, myRangeLenght);
NSString *forwardString = [maintextview.text substringFromIndex:backRange.location];
NSLog(#"%#",[[forwardString componentsSeparatedByString:#"."] objectAtIndex:1]);
}
forwadString contains the tapped text,i just want to highlight this string or draw a color above this text using core graphics or something like that.is out possible?
thanks in advance
Much to my and many other's disappointment, Apple chose not to implement NSAttributedString until iOS 3.2, and even then, all standard UI elements are incapable of rendering them!
Luckily, the few, the proud, and the brave have answered the call and DTCoreText was born.
As for an actual selection, because UITextView conforms to UITextInput as of iOS 3.2, you can use and set the selectedTextRange.
It's impossible to 'colour' an NSString, a string is just a representation of characters, it holds no font, colour or style properties. Instead you need to colour the UI element that draws the text to the screen.
If forwardString is in a UILabel or UITextView you can colour the text inside these by setting the textColor property. For example if you had a UILabel called lbl you could set the colour by using:
lbl.textColor = [UIColor redColor];

Justify Text in UILabel iOS

I am having a problem that in iOS I am using UILabel to display 2,3 line text, I want to align text as justified but I am not finding any option to do so. Any suggestions how to make justify text in label?
i put these line to make start it from top
CGSize maximumSize = CGSizeMake(300, 9999);
NSString *textString = someString;
UIFont *textFont = [UIFont fontWithName:#"Futura" size:14];
CGSize textStringSize = [textString sizeWithFont:textFont
constrainedToSize:maximumSize
lineBreakMode:text.lineBreakMode];
CGRect textFrame = CGRectMake(10, 110, 300, textStringSize.height);
text.frame = textFrame;
so any trick like this to make it justfiy
Thanks
There is now a convenient way to justify text since iOS6. You can create an instance of NSAttributedString, set appropriate properties and assign this attributed string to a text representing view such as UILabel, UITextView, etc. It's easy as this:
Create an instance of NSMutableParagraphStyle and set its properties.
NSMutableParagraphStyle *paragraphStyles = [[NSMutableParagraphStyle alloc] init];
paragraphStyles.alignment = NSTextAlignmentJustified; //justified text
paragraphStyles.firstLineHeadIndent = 10.0; //must have a value to make it work
Create NSDictionary for text attributes and create attributed string.
NSDictionary *attributes = #{NSParagraphStyleAttributeName: paragraphStyles};
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString: string attributes: attributes];
Set attributed string to a label.
existingLabel.attributedText = attributedString;
Can't be done I'm afraid - well not with UILabel.
You can use the UIWebView or a 3rd party library such as OHAttributedLabel
Happy Coding :)
Update:
This answer has been obsolete since iOS6. Please refer to Tankista's answer.
As mentionned by #martin, my class OHAttributedLabel can make this very easily.
(You will find it on my github and also find plenty of references to it on SO as well)
It can be done easily, but you need to use Core Text.
subclass a UIView, add an NSString property, create an NSAttributedString and pass kCTJustifiedTextAlignment value for the kCTParagraphStyleSpecifierAlignment key, then draw the NSAttributedString using Quartz or CoreText in your drawrect method.
edit: kCTParagraphStyleSpecifierAlignment key kCTJustifiedTextAlignment value should be used to create a CTParagraphStyleRef struct and passed in as a value for kCTParagraphStyleAttributeName key when creating the NSAttributedString.
SWIFT 4.x
version of approved answer:
Create an instance of NSMutableParagraphStyle and set its properties.
let justifiedParagraphStyles: NSMutableParagraphStyle = NSMutableParagraphStyle.init()
justifiedParagraphStyles.alignment = .justified //justified text
justifiedParagraphStyles.firstLineHeadIndent = 10.0 //must have a value to make it work
Create NSDictionary for text attributes and create attributed string.
let attributes = [NSAttributedStringKey.paragraphStyle: justifiedParagraphStyles]
let attributedString = NSAttributedString.init(string: string, attributes: attributes)
Set attributed string to a label.
existingLabel.attributedText = attributedString

Get truncated text from UILabel

Is there anyway I can get the truncated version of the text for a UILabel?
In short, I have a paragraph of text, and two UILabels - label A, which is 2 lines long, and label B, which is a variable height. Label A is above label B. The idea is that label A shows the first two lines of the paragraph of text, and upon a certain user action, label B because visible and displays the rest of the text.
I'm having trouble determining what should go in label B, as I don't know what's being shown in label A. I'd need to also remove the "..." from label A.
Note: I realize this is a bit convoluted but there are some good reasons for it, which I won't clutter up the question with.
I wonder if you could use the methods in the NSString UIKit Additions to figure out how much fits into label A.
A crude way might be to start with the first character of your text and test for the size it would take up (-sizeWithFont:forWidth:lineBreakMode: maybe?) and then keep adding characters one at a time until it doesn't fit into your label A any more.
I hope somebody else can come up with a better way to do this, but the above should work.
Update
Last night I looked a bit into Core Text for my own app and came across CTFramesetterSuggestFrameSizeWithConstraints. You could maybe use this to figure out how much of your string fits into the label, by looking at the fitRange in that function.
Update 2:
I think this should work, but I have just typed this in here, so it may not even compile:
UIFont *uiFont = [UIFont systemFontOfZise:13.0f]; // whichever font you're using
CTFontRef ctFont = CTFontCreateWithName((CFStringRef)uiFont.fontName, uiFont.pointSize, NULL);
NSDictionary *attr = [NSDictionary dictionaryWithObject:(id)ctFont forKey:(id)kCTFontAttributeName];
CFRelease(ctfont);
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:yourLabelText attributes:attr];
CTFrameSetterRef frameSetter = CTFrameSetterCreateWithAttributedString((CFAttributedStringRef)attrString);
[attrString release];
CFRange fitRange;
CTFrameSetterSuggestFrameSizeWithConstrains(
frameSetter,
CFRangeMake(0, 0),
NULL,
CGSizeMake(labelWidth, labelHeight),
&fitRange);
CFRelease(frameSetter);
CFIndex numberOfCharactersThatFit = fitRange.length;
thanks to Thomas Müller
be sure to set line break mode the myLabel to this:
myLabel.lineBreakMode = NSLineBreakByWordWrapping;
by this method you can get chunked strings that actually fit in the constrained size.
Here is the baked code:
- (NSArray *)truncate:(NSString *)text
{
NSMutableArray *textChunks = [[NSMutableArray alloc] init];
NSString *chunk = [[NSString alloc] init];
CTFramesetterRef frameSetter;
UIFont *uiFont = [UIFont systemFontOfSize:17.0f];
CTFontRef ctFont = CTFontCreateWithName((__bridge CFStringRef)uiFont.fontName, uiFont.pointSize, NULL);
NSDictionary *attr = [NSDictionary dictionaryWithObject:(__bridge id)ctFont forKey:(id)kCTFontAttributeName];
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:text attributes:attr];
CFRange fitRange;
while (attrString.length>0) {
frameSetter = CTFramesetterCreateWithAttributedString ((__bridge CFAttributedStringRef) attrString);
CTFramesetterSuggestFrameSizeWithConstraints(frameSetter, CFRangeMake(0,0), NULL, CGSizeMake(myLabel.frame.size.width, myLabel.frame.size.height), &fitRange);
CFRelease(frameSetter);
chunk = [[attrString attributedSubstringFromRange:NSMakeRange(0, fitRange.length)] string];
[textChunks addObject:chunk];
[attrString setAttributedString: [attrString attributedSubstringFromRange:NSMakeRange(fitRange.length, attrString.string.length-fitRange.length)]];
}
return textChunks;
}
For Label A, calculate approximate character that should fit perfectly for two lines, for the particular font you are using.
For label B, set variable Height that the whole text must fit into it.