美文网首页iOS高质量博客iOS DeveloperiOS基础控件
iOS设置textView行间距(动态+静态+各种bug的代码)

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

作者: passionHan | 来源:发表于2016-10-14 23:07 被阅读1903次

前言

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

静态的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

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

相关文章

网友评论

  • f1b498cc8499:解决了折磨我三天的bug,在通过设置富文本保持行间距的情况下,在输入汉字后再输入字母,我出现了输入错误,比如输入字母abc,那么textview里面实际出现的是aababc,每次输入一个字母都会把前面输入的所有字母都带进去,可是我又不希望拿掉富文本,你的办法解决了我大问题,谢谢
  • c412131e53e9:感谢您。
  • 22d4539f53cc:输入中文的时候,拼音背景色高度是行高+文字高度
  • jyouli:我必须登录上来给你赞一下!! 解决了我好几天的问题!网上一大堆都是有问题的代码,不负责任
    22d4539f53cc:点击输入的时候,点击最后一行, 就是点击不上,没有出键盘
    passionHan:@jyouli 谢谢,网上说的很多都是重复的,要自己去研究,很开心能帮助到你:blush:
  • hee678:整的那么复杂,新增一个判断就好了。
    - (void)textViewDidChange:(UITextView *)textView
    {
    // 判断是否有候选字符,如果不为nil,代表有候选字符
    if(textView.markedTextRange == nil){
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    paragraphStyle.lineSpacing = 10; // 字体的行间距
    paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;

    NSDictionary *attributes = @{NSFontAttributeName:[UIFont systemFontOfSize:15],
    NSParagraphStyleAttributeName:paragraphStyle
    };
    textView.attributedText = [[NSAttributedString alloc] initWithString:textView.text attributes:attributes];
    }
    }
    passionHan:@博士猫_BSM 没事的,能帮助到你太好了:blush:
    博士猫_BSM:太赞了,用了你这个方法,解决了问题。谢谢
    passionHan:@hee678 嗯,关于输入时候字符混乱问题,我现在的做法是你上面写的那样,判断markedTextRange属性,但是关于处理光标的问题,不知道你的能不能解决,一会到了公司去试一下,谢谢你啊:blush:
  • Civel_Xu:设置行距之后,输入光标是小的,往上滚动查看输入内容时,光标变大了和行距一样高 ,,,怎么解决
    passionHan:这个没有做过,但是好像没见过哪个app在输入框里面加网格线的,这个原生的控件估计不好实现
    Civel_Xu:@passionHan 有做过 textview 里面加网格线嘛 ?这个行距设置 总是会有点偏差 :sweat:
    passionHan:恩,确实有这问题,在textView改变了行间距之后,它的子视图UITextSelectionView的高度也变了,我试了其他的动态改变行高方法,还有设置固定的行高,光标的大小也会跟着改变,目前我还没有解决这个问题,我再研究一下,谢谢你提出这个问题啊,之前没有遇到过。

本文标题:iOS设置textView行间距(动态+静态+各种bug的代码)

本文链接:https://www.haomeiwen.com/subject/auggyttx.html