UITextView 模拟标签功能
需求需要实现一个 类似于微博文本中 标签的能力, 一般我们用 YYTextView 配合 YYTextParser
很容易可以写出来, 参考, 但是当我们必需需要用 UITextView
来实现的时候, 就很麻烦了, 因为 YYTextView
不是继承的 YYTextView
, 他们是兄弟关系, 强行替换需要修改所有引用该文本的逻辑, 风险较大.
怎么基于 UItextView
实现一套标签能力呢?
UItextView
实现标签需要哪些能力
文本高亮, 使用 UITextView
的 attributedText
实现即可
删除到标签的时候, 第一次自动选中标签, 第二次整体删除标签
长按系统键盘空格键, 能拖动标签, 光标需要跳过标签, 不能定位到标签内部
长按文本多选的时候, 光标也要能跳过标签
点击标签跳转, 参考 就好, 本次 demo 没实现.
实现
demo
源码 UITextView+WYTagUtils.m
初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #import "UITextView+WYTagUtils.h"
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(16, 100, WY_SCREEN_WIDTH - 32, 200)]; textView.layer.borderColor = UIColor.blueColor.CGColor; textView.layer.borderWidth = 1; textView.delegate = self; textView.returnKeyType = UIReturnKeySend; textView.enablesReturnKeyAutomatically = YES; textView.scrollsToTop = NO; textView.highlightAttrDic = @{ NSForegroundColorAttributeName : [UIColor greenColor], NSFontAttributeName : [UIFont systemFontOfSize:16], }; textView.normalAttrDic = @{ NSForegroundColorAttributeName : UIColor.grayColor, NSFontAttributeName : [UIFont systemFontOfSize:16], }; [self.view addSubview:textView];
|
按需设置标签内容
1 2 3 4 5
| for (NSString *text in @[@"@周杰伦", @"#每日推荐"]) { // 设置标签内容 [textView tu_appendTagString:WYSAFE_CAST(text, NSString)]; }
|
主动设置文本内容
1 2 3
| textView.text = @"一起听新歌吧 @周杰伦 最伟大的作品 @周杰伦的歌"; // 刷新高亮 [textView tu_refreshText];
|
还需要实现几个 UITextView
的代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| - (void)textViewDidChangeSelection:(UITextView *)textView { // 调整光标的位置 [textView tu_adjustCursorPosition]; } - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { // 遇到标签 不能编辑, 直接选中准备删除 if (NO == [textView tu_shouldChangeTextInRange:range replacementText:text]) { return NO; } return YES; }
- (void)textViewDidChange:(UITextView *)textView { // 刷新富文本 [textView tu_refreshText]; }
|
遇到的坑
中文输入法不能直接刷新 UITextView 的富文本, 第一个输入的字母会被识别成英文, 从第二个输入的字母才算, 十分影响用户体验.
只有系统的中文输入法有问题, 系统中文输入法还在输入, 文本区域实际已经出现了字母”zhou”, 并且有一个选中态, 但是对于第三方中文输入法, 一般在输入框不会提前输入字母, 也就没有这个问题.
解决办法是在输入的时候判定 markedTextRange
, 如果有就不替换富文本
1 2 3 4 5 6 7 8 9 10
| - (void)tu_refreshText { UITextRange *markedRange = [self markedTextRange]; UITextPosition *position = [self positionFromPosition:markedRange.start offset:0]; if (position) // 有中文候选词(系统默认中文输入法才有), 不能刷新富文本 { return ; } // ...高亮逻辑 }
|