DALinedTextView icon indicating copy to clipboard operation
DALinedTextView copied to clipboard

iOS7 lineHeight issue

Open ghost opened this issue 11 years ago • 5 comments

Does not work on iOS with uifont besides systemfont

With self.textView.font = [UIFont fontWithName:@"HelveticaNeue" size:20]; lines does not match the letters...

ios simulator screen shot 28 09 2013 12 15 58

ghost avatar Sep 28 '13 11:09 ghost

I'm checking but not resolve yet

You can check and change "CGFloat baseOffset = 7.0f + self.font.descender;" value. Hope this help!

mthuong avatar Sep 28 '13 15:09 mthuong

It's strange. because systemfont works and if you use a custom font (.ttf file) it works also.

ghost avatar Sep 28 '13 18:09 ghost

any updates?

ghost avatar Oct 08 '13 13:10 ghost

We need to use TextKit to resolve this issue.

waelsaad avatar Dec 12 '13 04:12 waelsaad

Unfortunately, the bugs in TextKit affecting this issue were not fixed in iOS 7.1 As JohnSD said, systemFont works, but the named font which is the system font does not work. I did some poking around, printing out line and descender height for a variety of fonts under iOS 6 vs 7, and the results are inconsistent, supporting the idea of bugs in TextKit.

I discovered that the error in line height is proportional to the font size. If a factor is introduced to allow for the error, it is proportional to font size. In playing with this idea, I discovered a factor can be used, but unfortunately, it is different for each named font.

This kFactor is multiplied by the pointSize of the font to adjust the lineHeight. This adjustment must be compensated for in the offsetY or else the lines will not be drawn in the entire visible region. I have pasted in a portion of DrawRect() with my comments denoted by "RAH".

So, here's the DrawRect code that allows me to compensate fairly successfully for the bugs in iOS 7:

    // Create un-mutated floats outside of the for loop.
    // Reduces memory access.
    CGFloat baseOffset = 7.0f + self.font.descender;  //  original constant is 7.0f
    CGFloat screenScale = [UIScreen mainScreen].scale;
    CGFloat boundsX = self.bounds.origin.x;
    CGFloat boundsWidth = self.bounds.size.width;

    //RAH xcode5      introduced k factor due to programming bugs by Apple
    //               in iOS 7 of UITextView.
    CGFloat kFactor = 0.0;
    BOOL isAtLeast7 = [[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0;
    if(isAtLeast7) {
        kFactor = self.font.pointSize * 0.03268;  // ArialMT  0.03267857143
        //kFactor = self.font.pointSize * 0.0;  // Helvetica
        //kFactor = self.font.pointSize * 0.028;  // Helvetica Neue (Regular)
        //kFactor = self.font.pointSize * 0.029;  // Helvetica Neue Thin
        //kFactor = self.font.pointSize * 0.029;  // Helvetica Neue Light
        //kFactor = self.font.pointSize * 0.0424;  // Times New Roman
    }

    // Only draw lines that are visible on the screen.
    // (As opposed to throughout the entire view's contents)
            //RAH   have to compute the "real" contentOffset to compensate for the kfactor
            //    or else as you scroll down a long page, the lines nearest the top won't be drawn.
    float realContentOffsetY = self.contentOffset.y - (self.contentOffset.y/self.font.lineHeight) * kFactor;
    NSInteger firstVisibleLine = MAX(1, (realContentOffsetY / self.font.lineHeight));
    //RAH  original code --  NSInteger firstVisibleLine = MAX(1, (self.contentOffset.y / self.font.lineHeight));
    NSInteger lastVisibleLine = ceilf((self.contentOffset.y + self.bounds.size.height) / self.font.lineHeight);

    for (NSInteger line = firstVisibleLine; line <= lastVisibleLine; ++line)
    {
        CGFloat linePointY = (baseOffset + ((self.font.lineHeight + kFactor) * line));
        // Rounding the point to the nearest pixel.
        // Greatly reduces drawing time.
        CGFloat roundedLinePointY = roundf(linePointY * screenScale) / screenScale;
        CGContextMoveToPoint(context, boundsX, roundedLinePointY);
        CGContextAddLineToPoint(context, boundsWidth, roundedLinePointY);
    }
    CGContextClosePath(context);
    CGContextStrokePath(context);
}

Rhyman avatar Apr 18 '14 21:04 Rhyman