Apply rich text format on selected text of UITextView in iOS - ios

I am creating an app in which i have to implement functionality like this:
1) Write into textview
2) Select text from textview
3) Allow user to apply bold,italic and underline functionality on selected text.
I have started implementing it using NSMutableAttributedString. It's working for bold and italic but replaces the textview text with only selected text.
-(void) textViewDidChangeSelection:(UITextView *)textView
{
rangeTxt = textView.selectedRange;
selectedTxt = [textView textInRange:textView.selectedTextRange];
NSLog(#"selectedText: %#", selectedTxt);
}
-(IBAction)btnBold:(id)sender
{
UIFont *boldFont = [UIFont boldSystemFontOfSize:self.txtNote.font.pointSize];
NSDictionary *boldAttr = [NSDictionary dictionaryWithObject:boldFont forKey:NSFontAttributeName];
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc]initWithString:selectedTxt attributes:boldAttr];
txtNote.attributedText = attributedText;
}
Can anybody please help me out to implement this functionality?
Thanks in advance.

You should not use didChangeSelection for this purpose. Use shouldChangeTextInRange instead.
This is because when you set the attributed string to new one you don't replace the text of certain location. You replace full text with your new text. You need range to locate the position where you want the text changed.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
NSMutableAttributedString *textViewText = [[NSMutableAttributedString alloc]initWithAttributedString:textView.attributedText];
NSRange selectedTextRange = [textView selectedRange];
NSString *selectedString = [textView textInRange:textView.selectedTextRange];
//lets say you always want to make selected text bold
UIFont *boldFont = [UIFont boldSystemFontOfSize:self.txtNote.font.pointSize];
NSDictionary *boldAttr = [NSDictionary dictionaryWithObject:boldFont forKey:NSFontAttributeName];
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc]initWithString:selectedString attributes:boldAttr];
// txtNote.attributedText = attributedText; //don't do this
[textViewText replaceCharactersInRange:range withAttributedString:attributedText]; // do this
textView.attributedText = textViewText;
return false;
}

Related

How to make textLabel on UITableViewCell with multiple colours?

I am using UITableview for listing names of person and also implement UISearchbar for searching different names.I want to change textLabel color on UITableViewCell when user searching on specific item,for example when i am typing name “Ant” on searchbar,need to change color of “Ant” on UItableview. Please help me.
You need to look at using NSAttributedString to specify the colour of the text. You will need to process the visible cells on each change in the search criteria and check when configuring cells for display, find the search text in the name string and set the appropriate format attributes for the found range.
You can use below method to fulfil your requirement.
- (NSAttributedString *)highlightText:(NSString *)textToBeHighlighted inString:(NSString *)fullString {
NSDictionary *attributeForFullText = #{
NSForegroundColorAttributeName : [UIColor blackColor],
NSFontAttributeName : [UIFont systemFontOfSize:10.0f]
// And more......
};
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:fullString attributes:attributeForFullText];
[attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:[fullString rangeOfString:textToBeHighlighted]];
/* you can use the above statement to do single style,
but if you want to do something more like size, font, alignment etc.
then you can do by below */
[attributedString addAttributes:dictionary_with_more_style range:[fullString rangeOfString:textToBeHighlighted]];
return attributedString;
}
And just call it from your cellForRowAtIndexPath
UILabel *titleLabel;
NSString *fullTitle;
NSString *searchString;
[titleLabel setAttributedText:[self highlightText:searchString inString:fullTitle];
You can make use of attributedText property of UILabel. This decorates the text on a label. Create a category for UITableViewCell and write a method and do the following:
#implementation UITableViewCell(asdf)
- (void)setText:(NSString *)text withMatchingText:(NSString *)matchingText;
{
// Set the default text color to the label text.
self.textLabel.textColor = // Default text color
if (matchingText.length > 0) {
// Create the color for the matching text.
UIColor *matchingColor = // Text color for the matching text, eg. "Ant"
//Find the range of the matching text from the whole text.
NSRange firstMatchingRange = [text rangeOfString:matchingText options:NSCaseInsensitiveSearch];
// Create an attributed string with matching color for your matching text on the whote text.
NSMutableAttributedString *mString = [[NSMutableAttributedString alloc] initWithString:text];
[mString addAttribute:NSForegroundColorAttributeName
value:matchingColor
range:firstMatchingRange];
self.textLabel.attributedText = mString;
}else {
self.textLabel.text = text;
}
}
In your viewController's tableView:cellForRowAtIndexPath: method do the following:
NSString *text = // the name property
cell setText:text withMatchingText:self.searchBar.text];
self.searchBar is the property of type UISearchBar you have on your ViewController connected with the search bar on your storyboard/xib.
The above code does like, If your search bar is having text then, It set the matchingColor to the matching text (eg. Ant) and the other letter(ony) will be the default colour. If no more matching text is there, then the whole text will be displayed with the default text colour.
This may help you.
Check this code. It may solve your problem.
Put this code in tableView:cellForRowAtIndexPath: method of your controller.
NSString *title = #"Test this answer";
NSString *searchText = #"ans";
NSMutableAttributedString *originalString = [[NSMutableAttributedString alloc] initWithString:title];
NSRange range = [title rangeOfString:searchText];
if (range.location == NSNotFound) {
NSLog(#"No match found");
}
else {
NSLog(#"Found the range of the substring at (%lu, %lu)", (unsigned long)range.location, range.location + range.length);
[originalString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:range];
}
cell.lbl_Title.attributedText = originalString;

Keep the colors of the textView text after appending NSSting

I'm using the next method to change the colors of few words in textView:
+(void)changeColorToTextObject : (UITextView *)textView ToColor : (UIColor *)color FromLocation : (int)location length : (int)length
{
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithAttributedString: textView.attributedText];
[text addAttribute:NSForegroundColorAttributeName value:color range:NSMakeRange(location, length)];
[textView setAttributedText: text];
}
and it looks like this:
but when i'm adding new value to this text the color are gone.
myTextView.text = [myTextView.text stringByAppendingString:newStr];
And it looks like this:
How can I keep the colors like before with the new string?
Instead of myTextView.text = [myTextView.text stringByAppendingString:newStr]; use:
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithAttributedString:myTextView.attributedText];
NSAttributedString *newAttrString = [[NSAttributedString alloc] initWithString:newStr];
[text appendAttributedString:newAttrString];
myTextView.attributedText = text;
Your code does not work because you are assigning to a new string to the text property of myTextView. text is just just a NSString property and thus is not able to display colors or other things that can be displayed using an NSAttributedString.
Note that writing myTextView.attributedText = text; calls the setter of the property attributedText and thus is 100% equivalent to [myTextView setAttributedText:text];, just a different notation.

Setting attributedText of UILabel causing issue with Lengthier content

In my project I want to add an attributed text in UILabel placed on the xib.
It's working perfectly, but if large text appears it shows some issues.
My current implementation:
- (void)viewDidLoad
{
[super viewDidLoad];
_demoLabel.numberOfLines = 0;
_demoLabel.lineBreakMode = NSLineBreakByWordWrapping;
_demoLabel.attributedText = [self demoNameWithFontSize:21 andColor:[UIColor redColor]];
}
- (NSMutableAttributedString *)demoNameWithFontSize:(CGFloat)fontSize andColor:(UIColor *)color
{
NSMutableAttributedString *attributedText = nil;
NSString *demoName = #"Blah blah blah";
UIFont *demoFont = [UIFont fontWithName:#"Zapfino" size:fontSize];
attributedText = [[NSMutableAttributedString alloc] initWithString:demoName];
NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init];
paragraph.lineBreakMode = NSLineBreakByWordWrapping;
[attributedText addAttribute:NSParagraphStyleAttributeName value:paragraph range:NSMakeRange(0, [demoName length])];
[attributedText addAttribute:NSFontAttributeName value:demoFont range:NSMakeRange(0, [demoName length])];
[attributedText addAttribute:NSForegroundColorAttributeName value:color range:NSMakeRange(0, [demoName length])];
return attributedText;
}
Output:
Issue:
It is not displaying the whole text, even if I applied the NSMutableParagraphStyle.
How can I solve this ?
Alternative I found:
If I change
UIFont *demoFont = [UIFont fontWithName:#"Zapfino" size:fontSize];
to
UIFont *demoFont = [UIFont systemFontOfSize:fontSize];
It'll work and gives output like:
But the issue is I need to use custom font, can't use default font. Also cannot change the font size.
I checked UILabel class reference and googled, but couldn't find a solution. Please help me.
Is there anyway to span this text into multiple lines ?
You need to resize the UILabel to fit the text.
You can calculate the size with the boundingRectWithSize:options:context: NSAttributedString class method, which takes an attributed string and calculates the size within a set rect based on all the attributes of the string.

Attribute for Multiple Text

I have this code and it's working (answer from https://stackoverflow.com/a/3586943/1187014), but I want try modify it a little bit :
NSString *text = #"Forgot password?";
if ([_labelForgotPassword respondsToSelector:#selector(setAttributedText:)])
{
// iOS6 and above : Use NSAttributedStrings
const CGFloat fontSize = 13;
UIFont *boldFont = [UIFont boldSystemFontOfSize:fontSize];
UIFont *regularFont = [UIFont systemFontOfSize:fontSize];
UIColor *foregroundColor = [UIColor whiteColor];
// Create the attributes
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
boldFont, NSFontAttributeName,
foregroundColor, NSForegroundColorAttributeName, nil];
NSDictionary *subAttrs = [NSDictionary dictionaryWithObjectsAndKeys:
regularFont, NSFontAttributeName, nil];
const NSRange range = NSMakeRange(16,0);
// Create the attributed string (text + attributes)
NSMutableAttributedString *attributedText =
[[NSMutableAttributedString alloc] initWithString:text
attributes:attrs];
[attributedText setAttributes:subAttrs range:range];
// Set it in our UILabel and we are done!
[_labelForgotPassword setAttributedText:attributedText];
} else {
// iOS5 and below
// Here we have some options too. The first one is to do something
// less fancy and show it just as plain text without attributes.
// The second is to use CoreText and get similar results with a bit
// more of code. Interested people please look down the old answer.
// Now I am just being lazy so :p
[_labelForgotPassword setText:text];
}
What if I have multiple text, let's say :
NSString *text1 = #"Forgot password?"; // relates with UILabel _labelForgotPassword
NSString *text2 = #"I agree with terms and condition"; // relates with UILabel _labelTerms
NSString *text3 = #"Your country is not listed yet?"; // relates with UILabel _labelCountry
First method that came into my mind is by having nested IF, but nested IF will be very ugly when I have lots of text which need to be attributed, right?
So, how to create that code into a method so that I can just supply the string, name of _label, range, etc and return the result to specific UILabel. and it's all triggered under viewDidLoad. Not by button pressed, or something else.
thank you.
What i am understanding is you want the same attributed logic to be applied to all labels. You can create a category on UILabel if you want to use it for only UILabels.
Syntax of the category should be something like this:
+(NSMutableAttributedString *) convertToAttributedText: (NSString *) text withFont: (UIFont *) font
{
// write the above logic here
//return the attributed text;
}
You can pass the text1 / text2 / text3 whatever to this api and you will get the attributed text.
label.attributedtext = [NSString convertToAttributedText: text withFont:font];
You can configure this API parameters based on your need.
Hope this helps.

Colour of a substring in a string of text view

I have text view like:
UITextview staticTxt = [[UITextView alloc]initWithFrame:CGRectMake(10, 80, 300, 400)];
staticTxt.backgroundColor = [UIColor clearColor];
staticTxt.text = #"this is a textview";
staticTxt.textColor = [UIColor whiteColor];
[self.view addSubview:staticTxt];
Now what i want is text "textview" should be in some different colour. How can i do this?
Thanks!!
You need to create an attributed text string, as described in this answer:
Underline text in a UITextView
First of all,You have to break your string into substrings. As you said in your comment,""this is a" is in white and "textview" is in red"... Am going to suggest you a way in that reference.
staticTxt.text = #"this is a textview";
NSString *yourString = staticTxt.text;
NSString *str = [[yourString componentsSeparatedByString:#"a "] lastObject];
Now you can set color of "str" substring.
Let me tell you one thing very clearly.It is way only to change substring color of static string.. If you are going to change the text of your textview dynamically... then this method is not a good choice...
You can use different color , different font and different size text in your control(UILabel, UITextField or UItextView) by using this class method
+ (void)setMultiColorAndFontText:(NSString *)text rangeString:(NSArray *)rangeString inputView:(UITextView*) inputView font:(NSArray*) fontName color:(NSArray*) colorName
{
inputView.layer.sublayers = nil;
NSMutableAttributedString *mutableAttributedString = [[ NSMutableAttributedString alloc]initWithString:text];
for (int i =0 ; i<[rangeString count]; i++)
{
CTFontRef ctFont = CTFontCreateWithName((__bridge CFStringRef) [UIFont fontWithName:[fontName objectAtIndex:i] size:14.0].fontName, [UIFont fontWithName:[fontName objectAtIndex:i] size:14.0].pointSize, NULL);
NSRange whiteRange = [text rangeOfString:[rangeString objectAtIndex:i]];
if (whiteRange.location != NSNotFound)
{
[mutableAttributedString addAttribute:(NSString *)kCTForegroundColorAttributeName value:(id)[colorName objectAtIndex:i] range:whiteRange];
[mutableAttributedString addAttribute:(NSString*)kCTFontAttributeName
value:( __bridge id)ctFont
range:whiteRange];
}
}
CGSize expectedinputViewSize = [text sizeWithFont:[UIFont fontWithName:#"Helvetica" size:14.0f] constrainedToSize:CGSizeMake(186,100) lineBreakMode:UILineBreakModeWordWrap];
CATextLayer *textLayer = [[CATextLayer alloc]init];
textLayer.frame =CGRectMake(0,4, inputView.frame.size.width,expectedinputViewSize.height+4);
textLayer.contentsScale = [[UIScreen mainScreen] scale];
textLayer.string=mutableAttributedString;
textLayer.opacity = 1.0;
textLayer.alignmentMode = kCAAlignmentLeft;
[inputView.layer addSublayer:textLayer];
[textLayer setWrapped:TRUE];
[inputView setText:#""];
}
Here you can pass your text , its range , font and color as parameters.
Example :
[CommonFunctions setMultiColorAndFontText:#"This is a textview" rangeString:[NSArray arrayWithObjects:#"This is a",#"textview", nil] textfield:txtEmailAddress font:[NSArray arrayWithObjects:#"Arial",#"Helvetica",nil] color:[NSArray arrayWithObjects:(UIColor *)[UIColor whiteColor].CGColor,(UIColor *)[UIColor redColor].CGColor,nil]];
It will display text with different color and different font.
Note : In this method we have used UITextView . If you need UILabel or UITextField then you just need to change it in same way like:
UILabel
+ (void)setMultiColorAndFontText:(NSString *)text rangeString:(NSArray *)rangeString inputView:(UILabel*) label font:(NSArray*) fontName color:(NSArray*) colorName;
UITextField
+ (void)setMultiColorAndFontText:(NSString *)text rangeString:(NSArray *)rangeString inputView:(UITextField*) label font:(NSArray*) fontName color:(NSArray*) colorName;
UITextView
+ (void)setMultiColorAndFontText:(NSString *)text rangeString:(NSArray *)rangeString inputView:(UITextView*) label font:(NSArray*) fontName color:(NSArray*) colorName;
Hope it helps you.

Resources