Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITextView and contentScaleFactor

I have a number of text contols in a scrollView that can be zoomed. In order to redraw the controls at a higher resolution to avoid blurry text, I set each view's contentScaleFactor in the view hierarchy as explained here. Everything works fine for labels and textfields but textViews do not redraw at the higher scale factor. I noticed that the only other subview for textViews that may make a difference if set is a private class UIWebDocumentView which implements content like UIWebView ( ie WebKit) but the new scale factor is ignored if set at either level ( UITextView or UIWebDocumentView ).

Any ideas how to reset the scale factor ( resolution ) for TextViews specifically ?

like image 943
pchronos Avatar asked Jun 18 '13 02:06

pchronos


2 Answers

Setting the contentScaleFactor and contentsScale is in fact the key, as @dbotha pointed out, however you have to walk the view and layer hierarchies separately in order to reach every internal CATiledLayer that actually does the text rendering. You also need to account for the screen scale.

The implementation would be something like this:

- (void)updateForZoomScale:(CGFloat)zoomScale {
    CGFloat screenAndZoomScale = zoomScale * [UIScreen mainScreen].scale;
    // Walk the layer and view hierarchies separately. We need to reach all tiled layers.
    [self applyScale:(zoomScale * [UIScreen mainScreen].scale) toView:self.textView];
    [self applyScale:(zoomScale * [UIScreen mainScreen].scale) toLayer:self.textView.layer];
}

- (void)applyScale:(CGFloat)scale toView:(UIView *)view {
    view.contentScaleFactor = scale;
    for (UIView *subview in view.subviews) {
        [self applyScale:scale toView:subview];
    }
}

- (void)applyScale:(CGFloat)scale toLayer:(CALayer *)layer {
    layer.contentsScale = scale;
    for (CALayer *sublayer in layer.sublayers) {
        [self applyScale:scale toLayer:sublayer];
    }
}

You can than call this when the zoom scale changes (part of UIScrollViewDelegate):

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {
    [self updateForZoomScale:scale];
}

I filed an enhancement request here: rdar://21443666 (http://www.openradar.me/21443666). There's also a sample project with the workaround attached.

like image 136
Matej Bukovinski Avatar answered Sep 30 '22 16:09

Matej Bukovinski


Be sure to apply the contentScaleFactor to all subviews of the UITextView. I've just tested the following with a UITextView and found it to work:

- (void)applyScale:(CGFloat)scale toView:(UIView *)view {
    view.contentScaleFactor = scale;
    view.layer.contentsScale = scale;
    for (UIView *subview in view.subviews) {
        [self applyScale:scale toView:subview];
    }
}
like image 32
dbotha Avatar answered Sep 30 '22 14:09

dbotha