NSTextView with long NSMutableAttributedText low scrolling and loading speed - ios

I have a uitextview that most of times should show long attributedtexts. I use below code for creating my attributed text:
//Add each line of doa to an element of array for future usage
NSArray *paragraphs = [self.Text componentsSeparatedByString:#"\r\n"];
MixedContent= [[NSMutableAttributedString alloc]init];
ArabicContent= [[NSMutableAttributedString alloc]init];
TranslatedContent= [[NSMutableAttributedString alloc]init];
NSString * temp=#"";
for (int i=0; i< paragraphs.count; i++) {
if([paragraphs[i] hasPrefix:#"$2."]){
temp= [paragraphs[i] stringByReplacingOccurrencesOfString:#"$2." withString:#"" options:1 range:NSMakeRange(0, 3)];
NSMutableAttributedString* tempMutable= [[NSMutableAttributedString alloc] initWithString:temp attributes:doaDescriptionAttributes];
//Go to next line
[tempMutable appendAttributedString:[[NSMutableAttributedString alloc] initWithString:#"\n\n"]];
[ArabicContent appendAttributedString: tempMutable];
[TranslatedContent appendAttributedString:tempMutable];
[MixedContent appendAttributedString:tempMutable];
}else if ([paragraphs[i] rangeOfString:#"$3."].location != NSNotFound){
temp= [paragraphs[i] stringByReplacingOccurrencesOfString:#"$3." withString:#"" options:1 range:NSMakeRange(0, 3)];
NSMutableAttributedString* tempMutable= [[NSMutableAttributedString alloc] initWithString:temp attributes:arabicDoaAttributes];
[MixedContent appendAttributedString:tempMutable];
[MixedContent appendAttributedString:[[NSMutableAttributedString alloc] initWithString:#"\n"]];
[ArabicContent appendAttributedString:tempMutable];
[ArabicContent appendAttributedString: [[NSMutableAttributedString alloc] initWithString:#" "]];
}else if ([paragraphs[i] rangeOfString:#"$4."].location != NSNotFound){
temp= [paragraphs[i] stringByReplacingOccurrencesOfString:#"$4." withString:#"" options:1 range:NSMakeRange(0, 3)];
NSMutableAttributedString* tempMutable= [[NSMutableAttributedString alloc] initWithString:temp attributes:arabicDoaAttributes];
[MixedContent appendAttributedString:tempMutable];
[MixedContent appendAttributedString:[[NSMutableAttributedString alloc] initWithString:#"\n"]];
[TranslatedContent appendAttributedString:tempMutable];
[TranslatedContent appendAttributedString: [[NSMutableAttributedString alloc] initWithString:#" "]];
}
temp=nil;
}
}
My text is contain 3 kind of text. Some description. Some Arabic text and their translation. Each of this part is showing with a specific color.
And I use this code for setting the text:
self.myTextView.attributedText= myAttributedText;
the problem is that when I set or change the text of this textview it takes about 2 seconds that app set or update the text. The waiting time is not good for my users.
Also when I scroll the textview it is not good at all. It scroll some paragraphs and then stop for and then scroll, stop and scroll,....
Actually it is slow on scrolling.
Is there any better ways for setting the text so that I have a better performance?
UPDATE
I ma thinking whethere it is possible to load the text by scrolling. Some thing like a lazy loader list but for uitextview. Is it possible?
UPDATE
When I add the text without any attributes. (I mean all lines with same color) The scroll works fine.
UPDATE
It is about the amount of texts. When I reduce the amount of texts. For example instead of setting 10000 character I set 500 character and now it is pretty fast. How can I fix it?

Related

Cannot set underline for UILabel [duplicate]

This question already has answers here:
How to make an underlined text in UILabel?
(7 answers)
Closed 4 years ago.
I have a UILabel which have text: "Something here and privacy policy", I just want to create underline for the text privacy policy but the code not affect. If I create underline for full text of my label then it worked, but it's not what I want.Here is my code:
NSString *str = self.myLabel.text;
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:str];
NSRange index = [str rangeOfString:#"privacy policy"];
if (index.location != NSNotFound){
[attributedString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:NSUnderlineStyleSingle] range:NSMakeRange(index.location, index.length)];
//if I change index.location by 0 then it worked,
//with the underline start at the begin text of mylabel but that not what I expected
[self.myLabel setAttributedText:attributedString];
}
Is have something wrong with my code(my app support for iOS 7 and latter)?
Please try this piece of code.
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 250, 40)];
label.font=[UIFont fontWithName:#"Helvetica" size:12];
label.textColor=[UIColor blackColor];
NSString *text = #"Something and Privacy Policy";
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc ]initWithString:text];
NSInteger location = [#"Something and " length]-1;
NSInteger length = [#"Privacy Policy" length];
[attrString addAttribute:NSUnderlineStyleAttributeName value:#(NSUnderlineStyleSingle) range:NSMakeRange(location, length)];
label.attributedText=attrString;
[self.view addSubview:label];
To temporarily fix your issue, you can split your String into 2 NSMutableAttributedString with latter string having text "privacy policy". You can then underline the whole text and concatenate the two strings.
NSString *str = self.myLabel.text;
NSRange index = [str rangeOfString:#"privacy policy"];
if (index.location != NSNotFound){
NSString *tempString = [str substringWithRange:NSMakeRange(0, index.location - 1)];
NSAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:tempString];
NSString *privacyString=[str substringFromIndex:index.location];
NSAttributedString *attributedString1 = [[NSMutableAttributedString alloc] initWithString:privacyString];
[attributedString1 addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:NSUnderlineStyleSingle] range:NSMakeRange(0, attributedString1.length)];
//with the underline start at the begin text of mylabel but that not what I expected
NSMutableAttributedString *mutableAttString = [[NSMutableAttributedString alloc] init];
[mutableAttString appendAttributedString: attributedString];
[mutableAttString appendAttributedString:attributedString1];
[self.myLabel setAttributedText:mutableAttString];
}
The best way I've found to underline a portion of a text is to use Interface Builder (Designer first, coder second). Granted this might not be what you want but for a temporary solution I propose the following:
Instructions
1) Place a UILabel in your viewController of choice and add constraints as needed.
2) Click on your label, replace the text and go to Attributes Inspector. (Image 1)
3) Change your UILabel from 'Plain Text' to 'Attributed'
4) Highlight the portion you want underlined as shown in Image 2 below and press the 'T' in a square.
5) On the toolbar of the window that shows up, you'll see an underlined 'T'. Select 'single' (Image 3).
Images

String and attributions problems

Ive been messing around with this without proper results. My code is as follows
NSMutableAttributedString *nameString = [[NSMutableAttributedString alloc]initWithString:((User *)appDelegate.users[self.currentUserIndex]).name];
[nameString addAttribute:NSFontAttributeName value:[UIFont fontWithName:#"Helvetica-Bold" size:12.0] range:NSMakeRange(0, nameString.length)];
NSString *adviceString = [[NSString alloc] initWithFormat:#"%#, remember be extra aware of the \n cat today. The dog index is 4, dogcatcher \n suggests you should at minimum wear \n a dog and apply cat...", [nameString string]];
So, it doesn't bold the username as desired. I tried using NSAttributedString for adviceString but then I can't use the initWithFormat: method and list the variables after the string, and I don't see any NSAttributedString equivalent. I wanted to you NSAttributedString instead of NSMutableAttributedString, but it doesn't seem to recognise the addAttribute:value:fontWithName:range method. Can anybody help me out? Any help much appreciated.
That's for sure, you need to use NSAttributedString also for adviceString to get attributed.
The code goes like this, if you need to use stringWithFormat:
NSString *fullName = #"Anoop Kumar Vaidya";
NSMutableAttributedString *attributedName = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:#"Hello %#", fullName]
attributes:#{NSFontAttributeName : [UIFont boldSystemFontOfSize:[UIFont systemFontSize]]}];
In the attributes you can add few more desired/required attributes.
EDIT 2:
You may like to use some methods as :
-(NSMutableAttributedString *)normalString:(NSString *)string{
return [[NSMutableAttributedString alloc] initWithString:string
attributes:#{}];
}
-(NSMutableAttributedString *)boldString:(NSString *)string{
return [[NSMutableAttributedString alloc] initWithString:string
attributes:#{NSFontAttributeName : [UIFont boldSystemFontOfSize:[UIFont systemFontSize]]
}];
}
And then use them as per your requirement:
NSMutableAttributedString *attributedName = [self boldString:fullName];
[attributedName appendAttributedString:[self normalString:#" is creating one"]];
[attributedName appendAttributedString:[self boldString:#" bold"]];
[attributedName appendAttributedString:[self normalString:#" string."]];

Display edited NSString in order

I have been working on this for a few days with help from this great community.
I have a NSArray that I need to edit NSStrings within. I have managed to detect a marker in the string and make it bold. However now I am trying to display the strings in the order that they are within the NSArray whilst maintaining the Bold that was added to the specific strings.
I can display the individual Bold String 'string' but I need it to be in order that it is within the array. I know of stringByAppendingString but this would put it at the end.
Any directions would be brilliant.
for (NSString *testWord in legislationArray) {
if ([testWord rangeOfString:#"BOLDME"].location != NSNotFound) {
//Remove Marker
NSString *stripped = [testWord stringByReplacingOccurrencesOfString:#"BOLDME" withString:#""];
//Get string and add bold
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:stripped];
NSRange selectedRange = [stripped rangeOfString:(stripped)];
[string beginEditing];
[string addAttribute:NSFontAttributeName
value:[UIFont fontWithName:#"Helvetica-Bold" size:18.0]
range:selectedRange];
[string endEditing];
//Where to go now with string?
}
}
cell.dynamicLabel.text = [legislationArray componentsJoinedByString:#"\n"];
EDIT
Based on the answers below I got it working however the bold method invokes this error:
componentsJoinedByString return a NSString, when you want a NSAttributedString.
Plus, you're setting your text to a receiver that awaits a NSString (cell.dynamicLabel.text), where what you want should be cell.dynamicLabel.attributedText.
Since there is no equivalent to componentsJoinedByString for a NSAttributedString return, you have to do it the oldway, with a for loop, starting with initializing a NSMutableAttributedString, and adding to it each components (that you may "transform") to it.
Here is a example and related question.
Just use additional array. Change your code to
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] init];
for (NSString *testWord in legislationArray) {
if ([testWord rangeOfString:#"BOLDME"].location != NSNotFound) {
//Remove Marker
NSString *stripped = [testWord stringByReplacingOccurrencesOfString:#"BOLDME" withString:#""];
//Get string and add bold
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:stripped];
NSRange selectedRange = [stripped rangeOfString:(stripped)];
[string beginEditing];
[string addAttribute:NSFontAttributeName
value:[UIFont fontWithName:#"Helvetica-Bold" size:18.0]
range:selectedRange];
[string endEditing];
//Where to go now with string?
[attrString appendAttributedString:string];
}
else
{
[attrString appendAttributedString:[[NSAttributedString alloc] initWithString:testWord]];
}
// NEW LINE
[attrString appendAttributedString:[[NSAttributedString alloc] initWithString:#"\n"]];
}
cell.dynamicLabel.attributedText = attrString;
UPDATE:
Your additional issue is not a error - this is a way how XCode shows attributed strings in debug window:

Select Bold and Italicized text from textField

How can I select only bold and italicized text entered by user in a textField/textView ?
We can make a selected text bold, italicized, underline and any combination of these three but what about its vice-versa.
*This is not specific to Mac OSX or iOS, solution in either one is good for me.
EDIT:
I tried by reading the text in attributed string as :
NSAttributedString *string=self.textView.string;
But as textView and textField returns NSString so all formatting is gone.
on iOS use attributedText properties with labels/textfields
on OSX use attributedStringValue
you can then enumerate through the attributedText's attributes and check each attribute. Ill whip up some code (osx & iOS)
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:#"none "];
id temp = [[NSAttributedString alloc] initWithString:#"bold " attributes:#{NSFontAttributeName: [UIFont boldSystemFontOfSize:12]}];
[str appendAttributedString:temp];
temp = [[NSAttributedString alloc] initWithString:#"italic " attributes:#{NSFontAttributeName: [UIFont italicSystemFontOfSize:12]}];
[str appendAttributedString:temp];
temp = [[NSAttributedString alloc] initWithString:#"none " attributes:#{NSFontAttributeName: [UIFont systemFontOfSize:12]}];
[str appendAttributedString:temp];
temp = [[NSAttributedString alloc] initWithString:#"bold2 " attributes:#{NSFontAttributeName: [UIFont boldSystemFontOfSize:12]}];
[str appendAttributedString:temp];
self.label.attributedText = str;
NSMutableString *italics = [NSMutableString string];
NSMutableString *bolds = [NSMutableString string];
NSMutableString *normals = [NSMutableString string];
for (int i=0; i<str.length; i++) {
//could be tuned: MOSTLY by taking into account the effective range and not checking 1 per 1
//warn: == might work now but maybe i'd be cooler to check font traits using CoreText
UIFont *font = [str attribute:NSFontAttributeName atIndex:i effectiveRange:nil];
if(font == [UIFont italicSystemFontOfSize:12]) {
[italics appendString:[[str mutableString] substringWithRange:NSMakeRange(i, 1)]];
} else if(font == [UIFont boldSystemFontOfSize:12]){
[bolds appendString:[[str mutableString] substringWithRange:NSMakeRange(i, 1)]];
} else {
[normals appendString:[[str mutableString] substringWithRange:NSMakeRange(i, 1)]];
}
}
NSLog(#"%#", italics);
NSLog(#"%#", bolds);
NSLog(#"%#", normals);
Now here is how to find it. Deducing a selection range from this should be easy peasy :)
Note: you can only have a continuous selection! neither on osx nor on ios can you select n parts of a textfield/textview

Right to left UILabels

I need to display a text using a UILabel ( can't use UIWebView ), and it sometimes contains both Hebrew and English. using UILabel's default settings the sentence gets mixed up and doesn't make sense. I have failed to found a way to make UILabel display text rtl.
Does anybody know anyway to do that, or a code that implements this?
Have a look at this SO, it contains some info on this subject that might help you out.
It seems to work for some by adding the code \u200F to the strings to be displayed.
NSString *RTFstr = "1. בבוקר"; //This could be any right-to-left string
NSString *directionalString = [#"\u200F" stringByAppendingString:[note text]];
[someUITextView setString:directionalString];
This will work
-(void)fnForWritingDirection:(UILabel*)label textFor:(NSString *)stringForText{
NSMutableAttributedString* attrStr = [[NSMutableAttributedString alloc] initWithString: [stringForText stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setBaseWritingDirection:NSWritingDirectionRightToLeft];
[attrStr addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [attrStr length])];
label.attributedText=attrStr;
}

Resources