Reputation: 633
I've been working on this for days, and I ALMOST have things working. The problem I have is that when I update the UIView content (by doubling the text string), the superview (UIScrollView) displays the updated content double-sized.
Basically, I have a UIViewController created in IB that has a UIScrollView attached. The UIScrollView creates programmatically it's child UIView. The UIView is supposed to display a small "Loading..." text (via Core Text), which then changes to the real content that is being loaded from a URL.
In my testing, I have replaced the "Loading..." text with a paragraph that is 2 lines larger then the UIScrollView. It displays correctly and scrolls perfectly.
When the URL finishes loading, I replace the paragraph with the exact same paragraph twice (double the string length). Then I do a setNeedDisplay on the child UIView. The UIView (using the same code in it's drawRect) gets the new bounds, draws the text, and updates the parent's (UIScrollView) contentSize.
When the screen on the emulator updates, what I have is the content displayed, but double the height, causing the second paragraph of text to be cutoff.
At then end of the child's drawRect I have NSLog'd the parent's frame, bounds, contentSize, etc, along with the child's frame & bounds. Everything looks correct to me...the child's frame and bounds are twice the height as they were, the parent's contentSize is double it's frame and bounds remain the same.
So, there must be another layer in there somewhere that is affecting the drawing, but I simply cannot find it. Any suggestions are welcomed.
Here's my content view's drawRect():
- (void)drawRect:(CGRect)rect
{
CTTextAlignment paragraphAlignment = kCTLeftTextAlignment;
CTParagraphStyleSetting setting[1] =
{
{ kCTParagraphStyleSpecifierAlignment, sizeof(paragraphAlignment), ¶graphAlignment },
};
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(setting, 1);
NSMutableAttributedString* string = [[[NSMutableAttributedString alloc] initWithString:longText attributes:
[NSDictionary dictionaryWithObjectsAndKeys:(id)helvetica, (NSString*)kCTFontAttributeName,
paragraphStyle, (NSString*)kCTParagraphStyleAttributeName, nil]] autorelease];
CFRelease(paragraphStyle);
[string addAttribute:(id)kCTFontAttributeName
value:(id)helvetica
range:NSMakeRange(0, [string length])];
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)string);
CGSize size = CTFramesetterSuggestFrameSizeWithConstraints(framesetter,
CFRangeMake(0, 0),
NULL,
CGSizeMake(rect.size.width - 3, CGFLOAT_MAX),
NULL);
[self setFrame:CGRectMake(0, 0, (int)(size.width + 0.5), (int)(size.height + 0.5))];
MyContentScroller* scroller = (MyContentScroller*)self.superview;
[scroller setContentSize:self.bounds.size];
CGMutablePathRef columnPath = CGPathCreateMutable();
CGRect bounds = CGRectMake(2, 2, self.bounds.size.width - 4, self.bounds.size.height);
CGPathAddRect(columnPath, NULL, bounds);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter,
CFRangeMake(0, 0),
columnPath, NULL);
CGPathRelease(columnPath);
CFRelease(framesetter);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CTFrameDraw(frame, context);
CFRelease(frame);
CGContextRestoreGState(context);
}
Upvotes: 1
Views: 1119
Reputation: 633
Okay, it seems that the problem has something to do with changing the size of the view from inside the drawRect function.
When I pulled out the framesetter initialization into it's own function, then had that function call the setNeedDisplay, that seemed to take care of the problem I was having.
-(void)updateText:(NSString*)textStr
{
if (textStr == longText) { return; }
longText = textStr;
CTTextAlignment paragraphAlignment = kCTLeftTextAlignment;
CTParagraphStyleSetting setting[1] =
{
{ kCTParagraphStyleSpecifierAlignment, sizeof(paragraphAlignment), ¶graphAlignment },
};
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(setting, 1);
NSMutableAttributedString* string = [[[NSMutableAttributedString alloc] initWithString:longText attributes:
[NSDictionary dictionaryWithObjectsAndKeys:(id)helvetica, (NSString*)kCTFontAttributeName,
paragraphStyle, (NSString*)kCTParagraphStyleAttributeName, nil]] autorelease];
CFRelease(paragraphStyle);
[string addAttribute:(id)kCTFontAttributeName
value:(id)helvetica
range:NSMakeRange(0, [string length])];
if (framesetter) { CFRelease(framesetter); }
framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)string);
CGSize size = CTFramesetterSuggestFrameSizeWithConstraints(framesetter,
CFRangeMake(0, 0),
NULL,
CGSizeMake(self.bounds.size.width - 4, CGFLOAT_MAX),
NULL);
[self setFrame:CGRectMake(0, 0, (int)(size.width + 0.5), (int)(size.height + 0.5))];
MyContentScroller* scroller = (MyContentScroller*)self.superview;
[scroller setContentSize:self.bounds.size];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
if (!framesetter) { return; }
CGMutablePathRef columnPath = CGPathCreateMutable();
CGRect bounds = CGRectMake(2, 2, self.bounds.size.width - 4, self.bounds.size.height);
CGPathAddRect(columnPath, NULL, bounds);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter,
CFRangeMake(0, 0),
columnPath, NULL);
CGPathRelease(columnPath);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CTFrameDraw(frame, context);
// CFRelease(frame); // This line causes a crash!
CGContextRestoreGState(context);
}
Upvotes: 1