iOS设置textView行间距(动态+静态+各种bug的代码)

前言

好久没有在简书上面发表文章了,至今文集中都还有好几个未完成的文章,今天决定先发表一篇简单好写的文章,也许我这看似简单的文章就能省去你几个小时的时间,来写更多的代码。哈哈,我相信基本上有需要这方面的功能,但是在网上搜索来实现的时候肯定遇到过坑,所以这篇文章你不会白看的。

静态的textView行间距

当我们不需要在textView中输入,直接显示文字时,设置textView的行间距非常简单,网上也有现成的代码,非常简单也不会有什么bug。

 UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(20, 100, 100, 200)];
    
    textView.delegate = self;
    
    textView.text = @"哈哈哈哈哈哈大家好大家好大家好大家好";
    
    [self.view addSubview:textView];
    
    NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
    
    paragraphStyle.lineSpacing = 20;// 字体的行间距
    
    NSDictionary *attributes = @{
                                 NSFontAttributeName:[UIFont systemFontOfSize:17],
                                 NSParagraphStyleAttributeName:paragraphStyle
                                 };
    textView.attributedText = [[NSAttributedString alloc] initWithString:textView.text attributes:attributes];

用到NSMutableParagraphStyle这个类,这是设置段落风格的类,有很多属性,请自行查看API

动态设置textView行间距

大多数情况下,我们的textView是需要输入的,我们想要在输入的时候改变行间距,上面的方法就行不通了。我们一贯的解决方法就是去网上查代码,基本上解决方案都是一样的,动态实现的话需要在textView的代理方法中实现。贴上bug代码。

- (void)textViewDidChange:(UITextView *)textView {
    
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    
    paragraphStyle.lineSpacing = 20;// 字体的行间距
    
    NSDictionary *attributes = @{
                                 NSFontAttributeName:[UIFont systemFontOfSize:15],
                                 NSParagraphStyleAttributeName:paragraphStyle
                                 };
    textView.attributedText = [[NSAttributedString alloc] initWithString:textView.text attributes:attributes];
}

这样,输入的时候间距出来了,但是内容就不准确了,输入的字符会直接显示到textView上,再次输入时前一次输入的还会显示上去,输入一个汉字会带上很多字符。如果是用模拟器运行就不会有这种bug。关于attributedText的具体实现没有深入去研究,如果我们换成另外一个属性就会显示正常了。

最终的方案

    UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(20, 100, 100, 200)];
    
    textView.delegate = self;
    
    [self.view addSubview:textView];
    
    NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
    
    paragraphStyle.lineSpacing = 20;// 字体的行间距
    
    NSDictionary *attributes = @{
                                 NSFontAttributeName:[UIFont systemFontOfSize:17],
                                 NSParagraphStyleAttributeName:paragraphStyle
                                 };
    textView.typingAttributes = attributes;

主要的一个属性 typingAttributes,官方文档中介绍是,该字典中包含属性键去应用于新输入的文本,当选择变化时字典的内容被自动清除,如果文本框不是在编辑模式中,这个属性为nil。同时你也不能赋值这个属性,除非文本字段目前处于编辑模式。所以这个属性不会出现使用attributedText的问题。

后续遇到的问题

以上的方案能够动态的改变UITextView的行间距,但是后来发现一个问题,当UITextView的行间距改变之后,光标的高度也跟着变化了,这样的用户体验不好。

image.png

后来查阅UITextView的API,没有发现相关的属性来设置光标的显示, 使用系统的UITextView暂时解决不了上述问题(如果有使用UITextView的解决方案,还请告知,谢谢!)。
但是,UITextView遵循了UITextInput协议,其中有返回光标frame的方法 *- (CGRect)caretRectForPosition:(UITextPosition )position,所以我们可以使用自定义的TextView,重写返回光标frame的方法来解决这个问题。

- (CGRect)caretRectForPosition:(UITextPosition *)position {
    CGRect originalRect = [super caretRectForPosition:position];
    
    originalRect.size.height = self.font.lineHeight + 2;
    originalRect.size.width = 3;
    
    return originalRect;
}

END

希望我这篇文章能帮助到阅读的你!

推荐阅读更多精彩内容