iOS:如何使用捏合手势调整UITextView的大小?

9

我希望创建一个 UITextView,它能够在输入文本时动态扩展,并且随着用户捏屏幕而进行缩放(TinyPost中可以找到类似的行为)。

当您仅输入文本时(未捏屏幕),textView 扩展得很好。当您仅捏屏幕时(未输入文本),它也正常工作,但当您捏屏幕然后输入文本时,内部的文本会被裁剪。

这是我的代码:

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  
    }

你认为呢?


2
为什么不将其包装到 UIScrollView 中,并从 viewForZoomingInScrollView: 方法返回文本视图呢? - user529758
5个回答

15

尝试:

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

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

    [self textViewDidChange:createTextView];       
}

它基本上会按比例缩放字体大小,然后使用你在textViewDidChange中编写的代码重新计算内容大小。


我建议您解释每行代码的作用。 - Allison
嗨@k20,我有同样的问题,我使用了textFiled,你能给我一些解决方案吗...谢谢。 - Ilesh P
如果您想在不更改字体属性的情况下缩放UITextView,请查看我的答案:https://dev59.com/0VbUa4cB1Zd3GeqPDfeo#44068200 - Slyv

2

首先在 viewDidLoad 方法中添加 UIPinchGestureRecognizer

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

然后将此方法放入您的viewController中以缩放textField字体:

- (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;

    }    
}

当对UITextView进行缩放时,原始的文本视图格式不应更改。但实际上会发生变化,加粗和斜体文本会转换为普通文本。 - Monika Patel
在我的情况下,这比所选答案更好 :) 谢谢! - Panayot

2
要详细解释一下@Cocoanetics的答案。我在iOS 7上实现了对带属性字符串的手势处理想法,但当您的字符串中有太多字体更改时,它会变得极其缓慢。此外,在iOS 7中存在一个荒谬的缓冲错误,即更改通知在你停止捏合后仍然不断地触发,这让我想起了早期版本PC-DOS中愚蠢的键盘缓冲区问题。无论如何,我在下面放置了我的代码,这使我意识到这是浪费时间的,我需要为我的用户提供其他方式来调整他们的字体大小。
- (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;
}

嗨,amergin。这段代码有什么改进吗?还是你已经放弃了它?谢谢你的回复。 - neowinston
@Winston - 是的,我放弃了字体缩放,现在只提供预设大小供用户选择。有点无聊,但我正在框架的限制内工作。也许将来会再试一次,看看底层代码是否有所改进。 - amergin
在我的情况下,它运行得非常好,因为我没有像你那样多的字体。现在我的唯一问题是限制最大和最小字体大小,以防止捏合手势使文本变得过大或过小,有时甚至消失。有什么建议吗?谢谢。 - neowinston
@Winston - 或许在getScaledStringFrom:方法中,可以先进行一次enumerateAttribute:调用,检查所有字体大小乘以比例后是否在最大值和最小值之间 - 如果在范围内,则执行上述的enumerateAttribute:调用。 - amergin
1
你的建议非常有效 :-) 我非常感谢你的帮助! - neowinston

0

UITextView是UIScrollView的子类,因此您需要像使用任何滚动视图一样进行以下操作以启用缩放:

  • 设置最小和最大缩放比例属性
  • 通过scrollview委托方法设置viewForZooming

...这将缩放整个文本视图。

如果您只想缩放文本,则必须通过捏合手势识别器执行以下步骤:

  • 检索当前的属性字符串
  • 遍历字体范围并替换字体属性为缩放后的属性
  • 使用修改后的版本替换文本视图中的文本
  • 在设置文本后可能还需要设置文本选择

1
你能否提供一些示例代码,以便遍历字体范围并增加UITextView属性字符串中的文本大小。我正试图做这件事。 - Duncan Groenewald
我目前手头没有它,基本上你只需要在属性字符串上枚举字体属性,然后用缩放后的字体替换它。 - Cocoanetics

0

不是最好的但容易的解决方案是:

我不知道你的具体用例,但我认为在许多情况下,在输入文本时支持应用程序捏合缩放没有意义。我只会设置一个标志,防止用户在输入文本时进行捏合缩放。

如果你所说的文本输入是指编辑文本视图,你可以在捏合手势开始时结束编辑,并在捏合手势结束后重新开始编辑。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接