I'm trying to scale editable attributed text in a UITextView and adjust the textView's width dynamically. I have no problem scaling the text with a UITextView inside a UIScrollView but I cannot work out what to change in order to retain the textView's width.
The above text is what I start with. Then I scale it and it is cropped to the UIScrollView's bounds.
But what I would really like is to be able to retain the original width and reflow the text as in this image.
I would really appreciate any help on this. I am using autolayout, iOS 7 and xcode 5.
I have tried scaling the fonts inside the string but there is a buffering bug in iOS7 which means the UIGestureRecognizerStateChanged notifications are buffered and the scaling continues long after the pinch gesture has ended for attributed strings with more than just a few font changes. For those interested this is the botch I have at the moment which does scale the fonts but not elegantly at all.
- (void)scaleTextView:(UIPinchGestureRecognizer *)pinchGestureRecognizer
{
CGFloat scale = 0;
NSMutableAttributedString *string;
switch (pinchGestureRecognizer.state) {
case UIGestureRecognizerStateBegan:
self.old_scale = 1.0;
self.last_time = [NSDate date];
break;
case UIGestureRecognizerStateChanged:
scale = pinchGestureRecognizer.scale - self.old_scale;
if( [self.last_time timeIntervalSinceNow] < -0.2 ) { // updating 5 times a second is best I can do - faster than this and we get buffered changes going on for ages!
self.last_time = [NSDate date];
string = [self getScaledStringFrom:[self.textview.attributedText mutableCopy] withScale:1.0 + scale];
if( string ) {
self.textview.attributedText = string;
self.old_scale = pinchGestureRecognizer.scale;
}
}
break;
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled:
case UIGestureRecognizerStateFailed:
break;
default:
break;
}
}
- (NSMutableAttributedString*) getScaledStringFrom:(NSMutableAttributedString*)string withScale:(CGFloat)scale
{
[string beginEditing];
[string enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, string.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) {
if (value) {
UIFont *oldFont = (UIFont *)value;
UIFont *newFont = [oldFont fontWithSize:oldFont.pointSize * scale];
[string removeAttribute:NSFontAttributeName range:range];
[string addAttribute:NSFontAttributeName value:newFont range:range];
}
}];
[string endEditing];
return string;
}
What I am looking for is the frame I need to change in the ScrollView, the TextView, the TextContainer, the LayoutManager or whatever which will cause my string to reflow within an adjusted border when the TextView within has been scaled/zoomed. Alternatively, if someone can correct or improve my code so that it is more performant I'd be extremely grateful.