iOS: Scaling UITextView with pinching?
Asked Answered
B

5

9

I'm interested in creating UITextView that is expanding dynamically while typing the text, and scaling as the user pinches the screen(Similar behaviour can be found in TinyPost).

When you just type (without pinching) the textView expands fine. When you just pinch (without typing) is works fine, but when you pinch and then type, the text inside gets cut.

Here is my code:

UIPinchGestureRecognizer *pinchGestRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(scaleTextView:)];
        pinchGestRecognizer.delegate = self;
        [bgFrameImageView addGestureRecognizer:pinchGestRecognizer];

    - (void)scaleTextView:(UIPinchGestureRecognizer *)pinchGestRecognizer{
        createTextView.transform = CGAffineTransformScale(createTextView.transform, pinchGestRecognizer.scale, pinchGestRecognizer.scale);

        pinchGestRecognizer.scale = 1;        
    }

    - (void)textViewDidChange:(UITextView *)textView{

        CGSize textSize = textView.contentSize;

        textView.frame = CGRectMake(CGRectGetMinX(textView.frame), CGRectGetMinY(textView.frame), textSize.width, textSize.height); //update the size of the textView  
    }

What do you think?

Bagworm answered 2/12, 2012 at 12:53 Comment(1)
Why don't you just wrap it into a UIScrollView and return the text view from the viewForZoomingInScrollView: method?Snafu
V
15

Try:

- (void)scaleTextView:(UIPinchGestureRecognizer *)pinchGestRecognizer{
     CGFloat scale = pinchGestRecognizer.scale;

    createTextView.font = [UIFont fontWithName:createTextView.font.fontName size:createTextView.font.pointSize*scale];

    [self textViewDidChange:createTextView];       
}

It basically scales the font size and then recalculates the content size using your code in textViewDidChange.

Veracruz answered 6/12, 2012 at 20:24 Comment(3)
I'de recommend that you explain what each line doesFarber
hi @k20, i have same problem and i use textFiled can u give me some solution ...Thanks..Deary
If you want to scale UITextView without changing font property, check my answer here: #5927723Photophore
D
2

To elaborate on @Cocoanetics answer above. I implemented the gesture handling idea for attributed strings on iOS 7 but it is prohibitively slow when you have too many font changes in your string. There is also a ridiculous buffering bug in iOS 7 where Change notifications keep firing long after you've stopped pinching - reminds me of the stupid keyboard buffer in early versions of PC-DOS. Anyway, I have put the code below that got this working for me - although it has only resulted in informing me that this is a waste of time and that I need to give my users some other way of scaling their fonts.

- (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;
}
Doley answered 20/6, 2014 at 20:40 Comment(5)
Hi amergin. Any improvements on this code or have you really abandoned it? Thanks for your reply.Polanco
@Winston - yeah, gave up on font scaling and just offering preset sizes for user to choose now. Bit lame but I'm working within the limitations of the frameworks. Might try it again in the future to see if underlying code has improved.Doley
In my case it's working really well, because I don't have as many fonts as you do. My only problem now is limiting the maximum and minimum font sizes to stop the pinching gesture so the text doesn't become too big or too small, and sometimes disappearing. Any suggestions? Thank you.Polanco
@Winston - maybe in getScaledStringFrom: just do a preliminary enumerateAttribute: call checking all font sizes multiplied by scale against a max and min size - if within bounds then do the enumerateAttribute: call above.Doley
Your suggestion worked really well :-) I appreciate very much your help!Polanco
R
2

First of all add UIPinchGestureRecognizer in viewDidLoad method:

UIPinchGestureRecognizer *pinchOnTextfield = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handleTextFieldFontOnAddMusicVc:)];
[self.myTextField addGestureRecognizer:pinchOnTextfield];

then put this method in your viewController to scale textField font:

- (void)handleTextFieldFontOnAddMusicVc:(UIPinchGestureRecognizer *)pinchGestRecognizer {
    if (pinchGestRecognizer.state == UIGestureRecognizerStateEnded || pinchGestRecognizer.state == UIGestureRecognizerStateChanged) {
        CGFloat currentFontSize = self.myTextField.font.pointSize;
        CGFloat newScale = currentFontSize * pinchGestRecognizer.scale;

        if (newScale < 20.0) {
            newScale = 20.0;
        }
        if (newScale > 60.0) {
            newScale = 60.0;
        }

        self.myTextField.font = [UIFont fontWithName:self.myTextField.font.fontName size:newScale];
        pinchGestRecognizer.scale = 1;

    }    
}
Rosenda answered 6/10, 2015 at 12:1 Comment(2)
When Zoom in & out apply to uitextview, that time original textview formatting should not chnage. But it will chnage and bold and italic text convert with simple textHamford
In my case, this is the better solution than the selected answer :) Thanks!Opener
B
0

UITextView is a subclass of UIScrollView and as such you need to do what you do with any scroll view to enable zooming:

  • set the minimum and maximum zoom scale properties
  • set the viewForZooming via the scrollview delegate method

... that zooms the entire text view.

If you only want to zoom the text then you have to perform these steps via a pinch gesture recognizer:

  • retrieve the current attributed string
  • walk through the font ranges and replace the font attribute with a scaled one
  • replace the text in the text view with your modified version
  • probably you also need to set the text selection after setting the text
Butcherbird answered 10/12, 2012 at 9:16 Comment(2)
any chance you could provide sample code for walking through the font ranges and increasing the text size in the uitextview's attributes string. I am trying to do just this.Dichromatic
I don't have it handy ATM, essentially you have to just enumerate the font attribute on the attributed string and then replace it with a scaled one.Butcherbird
D
0

Not the best but easy solution would be:

I do not know exactly your use case, but I think it does not make sense in many cases to support in a app pinch zoom while typing text. I would just set a flag, which prevents pinch zoom while user is typing text.

If you mean by text typing, editing the text view you can end the editing at the beginning of the pinch gesture and start editing after pinch gesture did end.

Digital answered 10/12, 2012 at 13:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.