UITextView scroll performance for large attributed strings - uitextview

How can scroll performance of a UITextView be improved when using attributed strings? The following sample code results in completely unacceptable performance on an iPad 3.
NSMutableParagraphStyle *pStyle = [[NSMutableParagraphStyle alloc] init];
pStyle.lineSpacing = 14.0;
pStyle.lineHeightMultiple = 20;
pStyle.maximumLineHeight = 20.0;
pStyle.minimumLineHeight = 20.0;
UIFont *font = [UIFont systemFontOfSize:20.0];
NSDictionary *attributes = #{ NSFontAttributeName : font, NSParagraphStyleAttributeName : pStyle};
NSMutableAttributedString *newline = [[NSMutableAttributedString alloc] initWithString:#"\n\n"];
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:#"" attributes:#{}];
for (int paragraph=0; paragraph<300; paragraph++){
for (int word=0; word<100; word++){
[string appendAttributedString:[[NSAttributedString alloc] initWithString:#"text!"]];
}
[string appendAttributedString:newline];
}
[string setAttributes:attributes range:NSMakeRange(0, string.length)];
self.textView.attributedText = string;
I should mention that I am open to using Text Kit, but I wouldn't know where to start to ensure that performance is ultimately ok. Also, here's what's going on in the profiler while scrolling.

Two things help here.
First, I only needed the lineSpacing style set. Setting any of the other paragraph parameters results in slow scrolling.
The second was to call [self.textView.layoutManager ensureLayoutForCharacterRange:NSMakeRange(0, self.textView.attributedText.length)]; in viewDidAppear:. Otherwise the first time you scroll through the document it is jerky.

Related

Cocos 2d CCmenu not appearing

I have recently coded in a menu item, the "Game Over" Label appears but the menu item "Restart" isn't. I have no idea why?
Can anyone help, here is whats in my method !
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCLabelTTF *label = [CCLabelTTF labelWithString:#"Game Over"
fontName:#"Marker Felt"
fontSize:64];
label.color = ccRED;
label.position = ccp(winSize.width*0.5, winSize.height*0.75);
[self addChild:label];
CCMenuItem *item = [CCMenuItemFont itemWithString:#"Restart"
target:self
selector:#selector(restartGame)];
CCMenu *menu = [CCMenu menuWithItems:item, nil];
[menu alignItemsVertically];
[self addChild:menu];
try this code:
menu.position = ccp(winSize.width/2, winSize.height/2);
set the specific position.

how to get string that fits to a constrained size such as UILabel

I have a very very long text, so instead of using UITextView, I want to truncate the text to small chunks that can fit to a label with width and height 300, 400, and based on number of chunks, I want to create UILabel dynamically and populate them with these chunks.
I have written a method but it seems doesn't return the actual strings that can fit. it returns shorter strings.
am I missing something?
is there anyway I can do this?
- (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);
CGSize framSize = CTFramesetterSuggestFrameSizeWithConstraints(frameSetter, CFRangeMake(0,0), NULL, CGSizeMake(myLabel.frame.size.width, myLabel.frame.size.height), &fitRange);
NSLog(#"height: %f", framSize.height);
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;
}
Yes, you need to add a paragraph style in order to get the width/height measure to work properly. See giving-framesetter-the-correct-line-spacing-adjustment. Note how CTFontGetLeading() is used to get the font leading and then this property is set vai CFAttributedStringSetAttributes().

UItextview will disregard line height when NSFontAttributeName is set

Well, Ive searched in several places and although some people allegedly have found fixes it doesn't seem to apply to my case.
I'm trying to procedurally set the line height of a few UItextviews like this :
UITextView *lab = [LocalTexts objectAtIndex:j];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineHeightMultiple = 50.0f;
paragraphStyle.maximumLineHeight = 50.0f;
paragraphStyle.minimumLineHeight = 50.0f;
NSString *string = lab.text;
NSDictionary *ats = #{
NSFontAttributeName : [UIFont fontWithName:#"DIN Medium" size:16.0f],
NSParagraphStyleAttributeName : paragraphStyle,
};
lab.attributedText = [[NSAttributedString alloc] initWithString:string attributes:ats];
Strange thing is that if I disable the NSFontAttributeName assignment, the line height will work, also, if I set the Paragraph style to have a certain paragraph height, that always works too, so the NSParagraphStyleAttribute IS NOT being fully ignored. I dont know if it is a bug or I'm actually doing something wrong.
I tried implementing it as pure CORE TEXT, but it is a bit too complex for the current scope of the project.
Hope someone can point me in the right direction. Thanks.
This is a known bug in NSHTMLWriter which is used by UITextView to convert your attributed string to HTML: http://www.cocoanetics.com/2012/12/radar-uitextview-ignores-minimummaximum-line-height-in-attributed-string/
You can use UITextView replacement we have in DTCoreText to render this text correctly: https://github.com/Cocoanetics/DTCoreText

core-plot CPTextStyle fontName read-only

I'm playing with core-plot and I'd like to set font family and size for axis title, so what I did is:
CPTextStyle *axisTitleTextStyle = [CPTextStyle textStyle];
axisTitleTextStyle.fontName = #"Helvetica Bold";
axisTitleTextStyle.fontSize = 14.0;
but when I compile I get the error:
error: object cannot be set - either readonly property or no setter found
How can I set font?
Thanks,
Max
CPTextStyle changed a while back. It is now immutable. There is a mutable variant called CPMutableTextStyle.
give this a try
CPTextStyle *axisTitleTextStyle = [[CPTextStyle alloc] init];
axisTitleTextStyle.fontName = #"Helvetica Bold";
axisTitleTextStyle.fontSize = 14.0;
self.graph.titleTextStyle = axisTitleTextStyle;
[axisTitleTextStyle release];

uiwebview zoom programmatically

I want to change the UIWebView zoom level programmatically.
I have tried these but they are not worked for me ;
UIScrollView *sv = [theWebView.subviews objectAtIndex:0];
[sv setZoomScale:50 animated:YES];
also,
[theWebView stringByEvaluatingJavaScriptFromString:#"document.body.style.zoom = 5.0;"];
Any idea?
This is the only way I could find to accomplish it:
(specify your own sizes if you wish, i was attempting to zoom out after typing into a form field)
UIScrollView *sv = [[webViewView subviews] objectAtIndex:0];
[sv zoomToRect:CGRectMake(0, 0, sv.contentSize.width, sv.contentSize.height) animated:YES];
I would use:
UIScrollView * sv = self.theWebview.scrollView;
[sv setZoomScale:50];
where self is the viewController containing the webView.
Your problem could be the size of your zoomScale exceeds the size of sv.maximumZoomScale.
UIScrollView * sv = yourwebview_outlet.scrollView;
[sv setZoomScale:50];

Resources