iOS UITextView如何实现类似微博的话题、提及用户效果
导读:本文共3258.5字符,通常情况下阅读需要11分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: #话题#最终效果是:编辑过程中#话题内容#实时高亮高亮部分可以响应点击事件1.高亮基本思路是:使用正则匹配出成对的#,再利用UITextView的富文本实现高亮效果。funcrefreshTopicStyle(){letregex=try!NSRegularExpression(pattern:"此处填写正则表达式",options:[... ...
目录
(为您整理了一些要点),点击可以直达。#话题#
最终效果是:
编辑过程中
#话题内容#
实时高亮
高亮部分可以响应点击事件
1.高亮
基本思路是:使用正则匹配出成对的#
,再利用UITextView
的富文本实现高亮效果。
funcrefreshTopicStyle(){letregex=try!NSRegularExpression(pattern:"此处填写正则表达式",options:[NSRegularExpression.Options.caseInsensitive])//注意点lettotalRange=NSMakeRange(0,(inputTextView.attributedText.stringasNSString).length)letresults=regex.matches(in:inputTextView.attributedText.string,options:NSRegularExpression.MatchingOptions.init(rawValue:0),range:totalRange)letattributedString:NSMutableAttributedString=NSMutableAttributedString(string:inputTextView.attributedText.string)attributedString.setAttributes(normalAttributes,range:totalRange)forresultinresults{attributedString.setAttributes(topicAttributes,range:result.range)}inputTextView.attributedText=attributedString}
这有一个注意点,计算 totalRange 前,先将 String 转成了 NSString,这是因为此处 NSRange 中的 length 需要的是 UTF-16
长度,也就是与 NSString 的 length 定义一致,而 Swift 中的 String 没有 length 只有 count,指的是字符数,当文本中出现 emoji
表情时,二者就不一致了。
当然,也有一些其他办法来处理,如:
letlengthA=inputTextView.textStorage.lengthletlengthB=inputTextView.attributedText.string.utf16.count
2.点击事件
实现高亮部分的点击事件,目前有3种实现方案:
直接给
UITextView
添加点击事件通过设置
LinkAttribute
,利用超文本链接的点击实现重写
UITextView
的touches...
方法
其中,第二种只限于在非编辑状态(即 textView.isEditable = false
)下的点击,故排除,①、③均可,本文采用第一种,主要实现如下:
inputTextView.addTapGesture(self,handler:#selector(tapAttributedText(tap:)))@objcprivatefunctapAttributedText(tap:UITapGestureRecognizer){guardtap.isKind(of:UITapGestureRecognizer.self),lettextView=tap.viewas?UITextViewelse{return}letlayoutManager=textView.layoutManagervartapLocation=tap.location(in:textView)tapLocation.x-=textView.textContainerInset.lefttapLocation.y-=textView.textContainerInset.topletcharacterIndex=layoutManager.characterIndex(for:tapLocation,in:textView.textContainer,fractionOfDistanceBetweenInsertionPoints:nil)forresultingetCheckResult(format:Constants.TopicRegularExpression,text:inputTextView.attributedText.string){ifresult.range.location<characterIndex,characterIndex<result.range.location+result.range.length{//此处响应点击事件MBProgressHUD.showOnlyText(to:self.view,title:"美好时光")return}}inputTextView.becomeFirstResponder()}
@提及用户
编辑过程中
@提及用户
实时高亮,且只允许选取的用户名高亮,手动输入不高亮;
点击删除键的时候,一次性删除整个高亮部分
1.高亮
记录位置
本来准备用正则匹配的,但因为只允许选取的用户名高亮,纯手动输入的不高亮,所以使用正则匹配就不合理了,这里采用实时记录、更新已选取用户名位置的方式实现。
///用来保存已选取用户信息的结构体structUserInfo{///用户名varuserName:String///位置信息varrange:NSRange///用于临时替换的等长字符串varplaceholder:String}
临时替换
因为#话题#
和@提及用户
可以同时存在,所以需要考虑可能互相影响的问题,比如@提及用户
中间可能出现#
,导致前后话题的正则匹配发生错乱。
解决方案是:先使用一个@
开头且与@提及用户
等长的字符串替换@提及用户
,再执行#话题#
的正则匹配,最后再换回来。
2.整体删除
删除操作分为两步:第一次点删除仅选中整个用户名(提醒用户是整体删除);第二次点删除才真的删除文本。
functextView(_textView:UITextView,shouldChangeTextInrange:NSRange,replacementTexttext:String)->Bool{iftext==""{for(num,user)inusersArray.enumerated(){//usersArray用于存放已选取的用户信息//②删除选中的用户名iftextView.selectedRange.location<=user.range.location&&NSMaxRange(user.range)<=NSMaxRange(textView.selectedRange){textView.replace(textView.selectedTextRange??UITextRange(),withText:"")returnfalse}//①选中用户名iftextView.selectedRange.length==0&&(textView.selectedRange.location==user.range.location+user.range.length){textView.selectedRange=user.rangereturnfalse}}}}
</div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
iOS UITextView如何实现类似微博的话题、提及用户效果的详细内容,希望对您有所帮助,信息来源于网络。