这篇文章主要介绍“iOS UITextView如何实现类似微博的话题、提及用户效果”,在日常操作中,相信很多人在iOS UITextView如何实现类似微博的话题、提及用户效果问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”iOS UITextView如何实现类似微博的话题、提及用户效果”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
最终效果是:
编辑过程中#话题内容#
实时高亮
高亮部分可以响应点击事件
基本思路是:使用正则匹配出成对的#
,再利用UITextView
的富文本实现高亮效果。
func refreshTopicStyle() {
let regex = try! NSRegularExpression(pattern: "此处填写正则表达式",
options:[NSRegularExpression.Options.caseInsensitive])
// 注意点
let totalRange = NSMakeRange(0, (inputTextView.attributedText.string as NSString).length)
let results = regex.matches(in: inputTextView.attributedText.string,
options: NSRegularExpression.MatchingOptions.init(rawValue: 0),
range: totalRange)
let attributedString: NSMutableAttributedString = NSMutableAttributedString(string: inputTextView.attributedText.string)
attributedString.setAttributes(normalAttributes, range: totalRange)
for result in results {
attributedString.setAttributes(topicAttributes, range: result.range)
}
inputTextView.attributedText = attributedString
}
这有一个注意点,计算 totalRange 前,先将 String 转成了 NSString,这是因为此处 NSRange 中的 length 需要的是 UTF-16
长度,也就是与 NSString 的 length 定义一致,而 Swift 中的 String 没有 length 只有 count,指的是字符数,当文本中出现 emoji
表情时,二者就不一致了。
当然,也有一些其他办法来处理,如:
let lengthA = inputTextView.textStorage.length
let lengthB = inputTextView.attributedText.string.utf16.count
实现高亮部分的点击事件,目前有3种实现方案:
直接给UITextView
添加点击事件
通过设置LinkAttribute
,利用超文本链接的点击实现
重写UITextView
的touches...
方法
其中,第二种只限于在非编辑状态(即 textView.isEditable = false
)下的点击,故排除,①、③均可,本文采用第一种,主要实现如下:
inputTextView.addTapGesture(self, handler: #selector(tapAttributedText(tap:)))
@objc private func tapAttributedText(tap: UITapGestureRecognizer) {
guard tap.isKind(of: UITapGestureRecognizer.self), let textView = tap.view as? UITextView else {
return
}
let layoutManager = textView.layoutManager
var tapLocation = tap.location(in: textView)
tapLocation.x -= textView.textContainerInset.left
tapLocation.y -= textView.textContainerInset.top
let characterIndex = layoutManager.characterIndex(for: tapLocation,
in: textView.textContainer,
fractionOfDistanceBetweenInsertionPoints: nil)
for result in getCheckResult(format: Constants.TopicRegularExpression, text: inputTextView.attributedText.string) {
if result.range.location < characterIndex, characterIndex < result.range.location + result.range.length {
// 此处响应点击事件
MBProgressHUD.showOnlyText(to: self.view, title: "美好时光")
return
}
}
inputTextView.becomeFirstResponder()
}
编辑过程中 @提及用户
实时高亮,且只允许选取的用户名高亮,手动输入不高亮;
点击删除键的时候,一次性删除整个高亮部分
记录位置
本来准备用正则匹配的,但因为只允许选取的用户名高亮,纯手动输入的不高亮,所以使用正则匹配就不合理了,这里采用实时记录、更新已选取用户名位置的方式实现。
/// 用来保存已选取用户信息的结构体
struct UserInfo {
/// 用户名
var userName: String
/// 位置信息
var range: NSRange
/// 用于临时替换的等长字符串
var placeholder: String
}
临时替换
因为#话题#
和@提及用户
可以同时存在,所以需要考虑可能互相影响的问题,比如@提及用户
中间可能出现#
,导致前后话题的正则匹配发生错乱。
解决方案是:先使用一个@
开头且与@提及用户
等长的字符串替换@提及用户
,再执行#话题#
的正则匹配,最后再换回来。
删除操作分为两步:第一次点删除仅选中整个用户名(提醒用户是整体删除);第二次点删除才真的删除文本。
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if text == "" {
for (num, user) in usersArray.enumerated() { // usersArray 用于存放已选取的用户信息
// ②删除选中的用户名
if textView.selectedRange.location <= user.range.location && NSMaxRange(user.range) <= NSMaxRange(textView.selectedRange) {
textView.replace(textView.selectedTextRange ?? UITextRange(), withText: "")
return false
}
// ①选中用户名
if textView.selectedRange.length == 0 && (textView.selectedRange.location == user.range.location + user.range.length) {
textView.selectedRange = user.range
return false
}
}
}
}
到此,关于“iOS UITextView如何实现类似微博的话题、提及用户效果”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。