iOS UIScrollView/UIView 以双倍大小显示更新的内容

标签 ios uiview uiscrollview

我已经为此工作了好几天,几乎可以正常工作。我遇到的问题是,当我更新 UIView 内容(通过将文本字符串加倍)时, super View (UIScrollView) 显示更新内容的两倍大小。

基本上,我在 IB 中创建了一个 UIViewController,它附加了一个 UIScrollView。 UIScrollView 以编程方式创建它的子 UIView。 UIView 应该显示一个小的“正在加载...”文本(通过 Core Text),然后该文本会更改为从 URL 加载的真实内容。

在我的测试中,我用比 UIScrollView 大 2 行的段落替换了“正在加载...”文本。它可以正确显示并完美滚动。

当 URL 完成加载时,我将段落替换为完全相同的段落两次(字符串长度加倍)。然后我在子 UIView 上执行 setNeedDisplay。 UIView(在它的 drawRect 中使用相同的代码)获取新边界、绘制文本并更新父级 (UIScrollView) 的 contentSize。

当模拟器上的屏幕更新时,我的是显示的内容,但是高度加倍,导致第二段文字被截断。

然后在 child 的 drawRect 结束时,我有 NSLog'd parent 的框架、边界、contentSize 等,以及 child 的框架和边界。在我看来一切都是正确的... child 的框架和边界是原来高度的两倍, parent 的 contentSize 是原来的两倍,框架和边界保持不变。

所以,那里一定有另一层影响了绘图,但我就是找不到它。欢迎提出任何建议。

这是我的内容 View 的 drawRect():

- (void)drawRect:(CGRect)rect
{    
    CTTextAlignment paragraphAlignment  = kCTLeftTextAlignment;
    CTParagraphStyleSetting setting[1] = 
    {
        {   kCTParagraphStyleSpecifierAlignment, sizeof(paragraphAlignment), &paragraphAlignment },
    };

    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);
}

最佳答案

好的,看来问题与从 drawRect 函数内部更改 View 的大小有关。

当我将 framesetter 初始化提取到它自己的函数中,然后让该函数调用 setNeedDisplay 时,这似乎解决了我遇到的问题。

-(void)updateText:(NSString*)textStr
{
    if (textStr == longText)   {   return; }

    longText = textStr;

    CTTextAlignment paragraphAlignment  = kCTLeftTextAlignment;
    CTParagraphStyleSetting setting[1] = 
    {
        {   kCTParagraphStyleSpecifierAlignment, sizeof(paragraphAlignment), &paragraphAlignment },
    };

    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);
}

关于iOS UIScrollView/UIView 以双倍大小显示更新的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6496603/

相关文章:

ios - objective-C 。 NSString 改为 NSCFNumber

ios - 如何检测 UIScrollView 中的触摸点

objective-c - 从使用 UIButton 元素注册的 IBAction 中删除 UIView

iphone - iOS 分页控件(导航)

ios - UILabel 右 anchor 不适用于 ScrollView swift

ios - 使用相同的证书签名但错误 : Embedded binary is not signed with the same certificate

ios - 有时会返回 Google 距离矩阵 ZERO_RESULTS

ios - `[UIView initWithFrame:]` : nullable or nonnull? 的冲突文档

iphone - 无法在 iOS 上以编程方式调整 UITableView 的大小

iphone - 在 iPhone 中向 ScrollView 添加多个按钮时如何避免延迟?