Get string of first line in a UILabel - ios

I have some text in a UILabel. I want to get the text of the first label in a string variable.
For example:
label.text = #"You make an object by creating an instance of a particular class. You do this by allocating the object and initializing it with acceptable default values. When you allocate an object, you set aside enough memory for the object and set all instance variables to zero. Initialization sets an object’s initial state—that is, its instance variables and properties—to reasonable values and then returns the object. The purpose of initialization is to return a usable object. You need to both allocate and initialize an object to be able to use it.";
Now I want to get the text of the first line in the UILabel.

1.Add CoreText.framework. 2. Import #import CoreText/CoreText.h>.
Then use below method -
-(NSArray *)getLinesArrayOfStringInLabel:(UILabel *)label
{
NSString *text = [label text];
UIFont *font = [label font];
CGRect rect = [label frame];
CTFontRef myFont = CTFontCreateWithName(( CFStringRef)([font fontName]), [font pointSize], NULL);
NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:text];
[attStr addAttribute:(NSString *)kCTFontAttributeName value:( id)myFont range:NSMakeRange(0, attStr.length)];
CFRelease(myFont);
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString(( CFAttributedStringRef)attStr);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0,0,rect.size.width,100000));
CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL);
NSArray *lines = ( NSArray *)CTFrameGetLines(frame);
NSMutableArray *linesArray = [[NSMutableArray alloc]init];
for (id line in lines)
{
CTLineRef lineRef = ( CTLineRef )line;
CFRange lineRange = CTLineGetStringRange(lineRef);
NSRange range = NSMakeRange(lineRange.location, lineRange.length);
NSString *lineString = [text substringWithRange:range];
CFAttributedStringSetAttribute((CFMutableAttributedStringRef)attStr, lineRange, kCTKernAttributeName, (CFTypeRef)([NSNumber numberWithFloat:0.0]));
CFAttributedStringSetAttribute((CFMutableAttributedStringRef)attStr, lineRange, kCTKernAttributeName, (CFTypeRef)([NSNumber numberWithInt:0.0]));
//NSLog(#"''''''''''''''''''%#",lineString);
[linesArray addObject:lineString];
}
[attStr release];
CGPathRelease(path);
CFRelease( frame );
CFRelease(frameSetter);
return (NSArray *)linesArray;
}
I found this answer from below url - How to get text from nth line of UILabel?
NSString *firstLineString = [[self getLinesArrayOfStringInLabel:yourLabel] objectAtIndex:0];

NSString *text = label.text;
//remove any leading or trailing whitespace or line breaks
text = [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
//find the the range of the first occuring line break, if any.
NSRange range = [text rangeOfString:#"\n"];
//if there is a line break, get a substring up to that line break
if(range.location != NSNotFound)
text = [text substringToIndex:range.location];

This may help you
var array = string.componentsSeparatedByString("\r")
This will separate the string with new line, and you can get the line wise text in array.

Related

How to arrange NSString word in this type format without adding space in UILabel

I want to make this type format to word arrange in NSString on UILabel like
but I try to make add extra white space according to upper line word length but another way to make this type format suppose using NSAttributesString.
You can do this using NSMutableAttributedString without adding extra white space.
First, create a method that returns NSMutableAttributedString like this-
-(NSMutableAttributedString*)setIndent:(NSString*) title value:(CGFloat) value {
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
style.alignment = NSTextAlignmentLeft;
style.firstLineHeadIndent = value;
NSMutableAttributedString *attrText = [[NSMutableAttributedString alloc] initWithString:title attributes:#{ NSParagraphStyleAttributeName : style}];
return attrText;
}
and use this method by the following way -
NSString *title = #"Charlie Chapline Cartoon";
NSArray* foo = [title componentsSeparatedByString: #" "];
NSMutableAttributedString *attrText5 = [[NSMutableAttributedString alloc] init];
CGFloat value = 0.0f;
for(int i = 0; i< foo.count; i++){
//change this value according to your need.
value = value + 20.0f;
[attrText5 appendAttributedString:[self setIndent:[NSString stringWithFormat:#"%#\n", foo[i]] value:value]];
}
_myLab.numberOfLines = 5;
_myLab.attributedText = attrText5;
Output:

iOS: Truncate a large string , and appending a suffix string

I need to display some text in two lines , e.g.
| a very large string string string |
| string string ... - a suffix string |
The whole text contains two part
a large description string, need be truncated
"-a suffix string", won't be truncated
How to implement it in iOS ?
If you set it to NSLineBreakByTruncatingMiddleit will truncate in the middle.
You have to set the lineBreakMode. You can either do that from Interface Builder or programmatically as follows
label.lineBreakMode = NSLineBreakByTruncatingMiddle;
another Solution
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;
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];
}
Just do this and let me know..

CGRect for selected UITextRange adjustment for multiline text?

I've used this answer in order to create a CGRect for a certain range of text.
In this UITextView I've set it's attributedText (so I've got a bunch of styled text with varying glyph sizes).
This works great for the first line of text that's left aligned, but it has some really strange results when working with NSTextAlignmentJustified or NSTextAlignmentCenter.
It also doesn't calculate properly when the lines wrap around or (sometimes) if there are \n line breaks.
I get stuff like this (this is center aligned):
When instead I expect this:
This one has a \n line break - the first two code bits were highlighted successfully, but the last one more code for you to see was not because the text wrapping isn't factored into the x,y calculations.
Here's my implementation:
- (void)formatMarkdownCodeBlockWithAttributes:(NSDictionary *)attributesDict
withHighlightProperties:(NSDictionary *)highlightProperties
forFontSize:(CGFloat)pointSize
{
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"`.+?`" options:NO error:nil];
NSArray *matchesArray = [regex matchesInString:[self.attributedString string] options:NO range:NSMakeRange(0, self.attributedString.length)];
for (NSTextCheckingResult *match in matchesArray)
{
NSRange range = [match range];
if (range.location != NSNotFound) {
self.textView.attributedText = self.attributedString;
CGRect codeRect = [self frameOfTextRange:range forString:[[self.attributedString string] substringWithRange:range] forFontSize:pointSize];
UIView *highlightView = [[UIView alloc] initWithFrame:codeRect];
highlightView.layer.cornerRadius = 4;
highlightView.layer.borderWidth = 1;
highlightView.backgroundColor = [highlightProperties valueForKey:#"backgroundColor"];
highlightView.layer.borderColor = [[highlightProperties valueForKey:#"borderColor"] CGColor];
[self.contentView insertSubview:highlightView atIndex:0];
[self.attributedString addAttributes:attributesDict range:range];
//strip first and last `
[[self.attributedString mutableString] replaceOccurrencesOfString:#"(^`|`$)" withString:#" " options:NSRegularExpressionSearch range:range];
}
}
}
- (CGRect)frameOfTextRange:(NSRange)range forString:(NSString *)string forFontSize:(CGFloat)pointSize
{
self.textView.selectedRange = range;
UITextRange *textRange = [self.textView selectedTextRange];
CGRect rect = [self.textView firstRectForRange:textRange];
//These three lines are a workaround for getting the correct width of the string since I'm always using the monospaced Menlo font.
rect.size.width = ((pointSize / 1.65) * string.length) - 4;
rect.origin.x+=2;
rect.origin.y+=2;
return rect;
}
Oh, and in case you want it, here's the string I'm playing with:
*This* is **awesome** #mention `code` more \n `code and code` #hashtag [markdown](http://google.com) __and__ #mention2 {#FFFFFF|colored text} This**will also** work but ** will not ** **work** Also, some `more code for you to see`
Note: Please don't suggest I use TTTAttributedLabel or OHAttributedLabel.
I think all your problems are because of incorrect order of instructions.
You have to
Set text aligment
Find required substrings and add specific attributes to them
And only then highlight strings with subviews.
Also you will not need to use "a workaround for getting the correct width of the string since I'm always using the monospaced Menlo font" in such a case.
I have simplified your code a little to make it more understandable.
Result:
- (void)viewDidLoad
{
[super viewDidLoad];
NSDictionary *basicAttributes = #{ NSFontAttributeName : [UIFont boldSystemFontOfSize:18],
NSForegroundColorAttributeName : [UIColor blackColor] };
NSDictionary *attributes = #{ NSFontAttributeName : [UIFont systemFontOfSize:15],
NSForegroundColorAttributeName : [UIColor darkGrayColor]};
_textView.attributedText = [[NSAttributedString alloc] initWithString:
#"*This* is **awesome** #mention `code` more \n `code and code` #hashtag [markdown](http://google.com) __and__ #mention2 {#FFFFFF|colored text} This**will also** work but ** will not ** **work** Also, some `more code for you to see`" attributes:attributes];
_textView.textAlignment = NSTextAlignmentCenter;
[self formatMarkdownCodeBlockWithAttributes:basicAttributes];
}
- (void)formatMarkdownCodeBlockWithAttributes:(NSDictionary *)attributesDict
{
NSMutableString *theString = [_textView.attributedText.string mutableCopy];
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"`.+?`" options:NO error:nil];
NSArray *matchesArray = [regex matchesInString:theString options:NO range:NSMakeRange(0, theString.length)];
NSMutableAttributedString *theAttributedString = [_textView.attributedText mutableCopy];
for (NSTextCheckingResult *match in matchesArray)
{
NSRange range = [match range];
if (range.location != NSNotFound) {
[theAttributedString addAttributes:attributesDict range:range];
}
}
_textView.attributedText = theAttributedString;
for (NSTextCheckingResult *match in matchesArray)
{
NSRange range = [match range];
if (range.location != NSNotFound) {
CGRect codeRect = [self frameOfTextRange:range];
UIView *highlightView = [[UIView alloc] initWithFrame:codeRect];
highlightView.layer.cornerRadius = 4;
highlightView.layer.borderWidth = 1;
highlightView.backgroundColor = [UIColor yellowColor];
highlightView.layer.borderColor = [[UIColor redColor] CGColor];
[_textView insertSubview:highlightView atIndex:0];
}
}
}
- (CGRect)frameOfTextRange:(NSRange)range
{
self.textView.selectedRange = range;
UITextRange *textRange = [self.textView selectedTextRange];
CGRect rect = [self.textView firstRectForRange:textRange];
return rect;
}
I just had to do something similar to this. Assuming you are using iOS 7:
// Build the range that you want for your text
NSRange range = NSMakeRange(location, length);
// Get the substring of the attributed text at that range
NSAttributedString *substring = [textView.attributedText attributedSubstringFromRange:range];
// Find the frame that would enclose the substring of text.
CGRect frame = [substring boundingRectWithSize:maxSize
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
context:nil];
This should use the NSTextAlignment assigned to the attributed string.
As #Avt answered https://stackoverflow.com/a/22572201/3549781 this question. I'm just answering for the newline problem. This newline problem occurs on iOS 7+ even if you use
[self.textView selectedTextRange] or [self.textView positionFromPosition: offset:]
We just have to ensure the layout of the textView before calling firstRectForRange by
[self.textView.layoutManager ensureLayoutForTextContainer:self.textView.textContainer];
Courtesy : https://stackoverflow.com/a/25983067/3549781
P.S : At first I added this as a comment to the question. As most people don't read comments I added this as an answer.

Replace the truncation ellipsis of UILabel in iOS 7

How can I replace the truncation ellipsis ("…") of a UILabel in iOS 7 with another attributed character? For example, with a colored ">".
I was hoping Text Kit's NSLayoutManager would make this possible, but it appears UILabel doesn't make it public if it uses it.
Also, can I safely assume that an ellipsis is used as the truncation character in every localisation? Maybe different languages have different truncation characters.
I recommend you use TTTAttributedLabel, just set property "attributedTruncationToken" to your custom string.
I don't think it gives you access to this. I think you would have do handle it manually. For example, use TextKit to determine the size of your string, if it doesn't fit in the available area, truncate it yourself and append a ">" and then put your new string in the label.
NSAttributedString has methods for getting the size of the string.
Let me know if you need any more detail on this..?
I think you can do some customization in -replaceElipsesForLabel method provided by Fonix to get your desired result.
I have written a method to do it, and works in iOS7
-(void)setCustomEllipsis:(NSString*)customEllipsis inLabel:(UILabel*)label with:(NSString*)string{
//Replace the ellipsis
NSMutableString* result = [[NSMutableString alloc] initWithString:#""];
NSArray* strings = [string componentsSeparatedByString:#" "];
for (NSString* s in strings) {
CGRect newSize = [[NSString stringWithFormat:#"%#%#%#",result,s,customEllipsis] boundingRectWithSize:CGSizeMake(label.frame.size.width,0) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:label.font} context:nil];
if (newSize.size.height < label.frame.size.height) {
[result appendString:s];
[result appendString:#" "];
}else{
[result appendString:customEllipsis];
break;
}
}
[label setText:result];
//Set different font to the ellipsis
const CGFloat fontSize = 13;
UIFont *boldFont = [UIFont boldSystemFontOfSize:fontSize];
UIFont *regularFont = [UIFont systemFontOfSize:fontSize];
UIColor *foregroundColor = [UIColor lightGrayColor];
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:regularFont, NSFontAttributeName,foregroundColor, NSForegroundColorAttributeName, nil];
NSDictionary *subAttrs = [NSDictionary dictionaryWithObjectsAndKeys:boldFont, NSFontAttributeName, nil];
const NSRange range = [label.text rangeOfString:customEllipsis];
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:result
attributes:attrs];
[attributedText setAttributes:subAttrs range:range];
[label setAttributedText:attributedText];
}

NSKernAttributeName of a UITextView always 0

I'm setting an NSKernAttributeName to varying float values on the attributedText property of a UITextView on iOS 6, and within specific ranges. Every time the value is retrieved using the enumerateAttribute options block method of the attributedText, the Kerning is set to 0. Code is below.
Retrieval
NSAttributedString *currentText = _textView.attributedText;
[currentText enumerateAttribute:NSKernAttributeName inRange:NSMakeRange(0, currentText.length) options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired usingBlock:^(id value, NSRange range, BOOL *stop){
float value = [(NSNumber *)value floatValue];
//Do something with value, but logs show value is always 0
}];
Storage
NSMutableAttributedString *updatedText = self.textView.attributedText.mutableCopy;
_kernValue += 0.1f;
NSDictionary *attributes = #{
NSForegroundColorAttributeName: UIColor.linkColor,
NSFontAttributeName: [UIFont systemFontOfSize:14.0],
NSKernAttributeName: [NSNumber numberWithFloat:_kernValue]
};
NSMutableAttributedString *replacementString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:#"%# ", myString] attributes:attributes];
[updatedText replaceCharactersInRange:myRange withAttributedString:replacementString];
self.textView.attributedText = updatedText;
From the NSAttributedString header:
UIKIT_EXTERN NSString *const NSKernAttributeName NS_AVAILABLE_IOS(6_0); //
NSNumber containing floating point value, in points; amount to modify default kerning. 0 means kerning is disabled. (note: values other than nil and 0 are unsupported on iOS)

Resources