CTFramesetterSuggestFrameSizeWithConstraints with clipping attributes returning zero height

后端 未结 1 1128
走了就别回头了
走了就别回头了 2021-01-03 09:54

H! I\'m writing a textview with subviews clipping features. The idea is to make all text draw around all subviews. The problem is to get it\'s content height.

Due to

相关标签:
1条回答
  • 2021-01-03 10:13

    This seems to me like an iOS7 bug. I have been tinkering around, and under iOS6, CTFramesetterSuggestFrameSizeWithConstraints returns a size with height larger than 0. Same code under iOS7 returns a height of 0.

    CTFramesetterSuggestFrameSizeWithConstraints is known for its buggy and undocumented behavior. For example, your code under iOS6 returns an incorrect height due to CTFramesetterSuggestFrameSizeWithConstraints performing an incorrect calculation, and the last line is omitted from the calculation. Here is your code running under iOS6:

    enter image description here

    You should open a bug report for these issues, as well as request documentation enhancements, at: https://bugreport.apple.com

    Under iOS7, with TextKit, you can achieve the same result much quicker and more elegantly:

    @interface LeoView : UIView
    
    @property (nonatomic, assign) UIEdgeInsets contentInset;
    @property (nonatomic, retain) NSLayoutManager* layoutManager;
    @property (nonatomic, retain) NSTextContainer* textContainer;
    @property (nonatomic, retain) NSTextStorage* textStorage;
    
    @end
    
    @implementation LeoView
    
    -(void)awakeFromNib
    {
        //Leo: This should not be done here. Just for example. You should do this in the init.
    
        self.textStorage = [[NSTextStorage alloc] initWithString:@"Lorem ipsum dolor [...]"];
    
        self.layoutManager = [[NSLayoutManager alloc] init];
        [self.textStorage addLayoutManager:self.layoutManager];
    
        self.textContainer = [[NSTextContainer alloc] initWithSize:self.bounds.size];
        [self.layoutManager addTextContainer:self.textContainer];
    }
    
    - (void)layoutSubviews
    {
        [super layoutSubviews];
    
        //Leo: At this point the user may have set content inset, so need to take into account.
        CGSize size = self.bounds.size;
        size.width -= (self.contentInset.left + self.contentInset.right);
        size.height -= (self.contentInset.top + self.contentInset.bottom);
    
        self.textContainer.size = size;
    
        NSMutableArray* exclussionPaths = [NSMutableArray new];
        for (UIView* subview in self.subviews)
        {
            if(subview.isHidden)
                continue;
    
            CGRect frame = subview.frame;
            //Leo: If there is content inset, need to compensate.
            frame.origin.y -= self.contentInset.top;
            frame.origin.x -= self.contentInset.left;
    
            [exclussionPaths addObject:[UIBezierPath bezierPathWithRect:frame]];
        }
        self.textContainer.exclusionPaths = exclussionPaths;
    
        [self setNeedsDisplay];
    }
    
    - (void)drawRect:(CGRect)rect
    {
        [self.layoutManager drawGlyphsForGlyphRange:[self.layoutManager glyphRangeForTextContainer:self.textContainer] atPoint:CGPointMake(self.contentInset.left, self.contentInset.top)];
    
        //Leo: Move used rectangle according to content inset.
        CGRect usedRect = [self.layoutManager usedRectForTextContainer:self.textContainer];
        usedRect.origin.x += self.contentInset.left;
        usedRect.origin.y += self.contentInset.top;
    
        CGAffineTransform transform = CGAffineTransformIdentity;
        transform = CGAffineTransformScale(transform, 1, -1);
        transform = CGAffineTransformTranslate(transform, 0, -rect.size.height);
    
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextConcatCTM(context, transform);
        CGPathRef highlightPath = CGPathCreateWithRect(usedRect, &transform);
        CGContextSetFillColorWithColor(context, [UIColor colorWithRed:.0 green:1 blue:.0 alpha:.3].CGColor);
        CGContextAddPath(context, highlightPath);
        CGContextDrawPath(context, kCGPathFill);
        CFRelease(highlightPath);
    }
    
    @end
    

    And here is the result with contentInset set to UIEdgeInsetsMake(20, 200, 0, 35):

    enter image description here

    I used your code for drawing the green rectangle around the text.

    0 讨论(0)
提交回复
热议问题