前言
项目做了个搜索功能, 这个搜索功能有个很烦的显示样式, 这个样式竟然花了我两天的时间去搞定. 我才不是一个菜鸟程序猿
代码地址: https://github.com/gityuency/Autolayout
需求概述
- 在文本框里面输入文本, 将输入的字符和目标字符进行匹配, 把匹配到的结果显示在 Label 上, (其实就是使用一下网易云信的文本搜索功能,把搜索到的消息显示出来.)
- 如果这条消息很短, 那么, 在 Label 上完全显示, 这个没有问题.
- 如果这个消息很长, 那么 Label 是显示不全的, 这个时候, 要把匹配到的字符高亮显示出来.
- 如果匹配到的字符在目标字符串中间, 那么 Label 前后打上省略号.
- 如果匹配到的字符在目标字符串后面, 那么 Label 前面打上省略号.
- 如果匹配到的字符在目标字符串前面, 那么 Label 后面打上省略号.
- 如果目标字符串有多个子串被匹配到了, 那么取左边开始第一个匹配的到的子串并高亮.
我觉得作为一个程序猿, 上面的需求我写的很清晰.
效果图
搜索.gif
关键代码
(注意, 这并不是全部代码, 这段关键代码引用了一个 字符串扩展用来查找位置, 一个 富文本扩展用来高亮显示, 完整示例请下载项目)
/// 搜索文本的显示工具
class MessageDisplayTool {
/// 匹配字符串,更改 Label 显示样式
static func handleDisplayMessage(searchTxt: String, oriString: String, messageLabel: UILabel) {
messageLabel.superview?.layoutIfNeeded()
/// 除掉多余的换行
let fatherString = oriString.replacingOccurrences(of: "\r", with: "").replacingOccurrences(of: "\n", with: "")
/// 找到匹配文本从左到右第一次出现的位置
let position1 = fatherString.lowercased().positionOf(sub: searchTxt.lowercased())
if position1 < 0 {
messageLabel.text = searchTxt
return
}
let labelWidth = messageLabel.frame.size.width
let labelFont = messageLabel.font ?? UIFont.systemFont(ofSize: 17.0)
var indexFirst = position1 < 0 ? 0 : (position1 + searchTxt.count)
indexFirst = (indexFirst + 3) < fatherString.count ? (indexFirst + 3) : indexFirst //如果搜索的文本出现在了目标文本中间, 为了显示好看, 多往后显示3个文字
let i1 = fatherString.index(fatherString.startIndex, offsetBy: indexFirst)
let actuallyCleanURL = fatherString[..<i1]
let finalString = String(actuallyCleanURL)
let size: CGSize = finalString.size(withAttributes: [NSAttributedStringKey.font: labelFont]) //取第一次匹配到的结果,往后多截3个文字,然后拿宽度去比较
let of2 = position1 < 0 ? 0 : position1
let start = fatherString.index(fatherString.startIndex, offsetBy: of2)
let i2String = fatherString[start..<fatherString.endIndex] //这里取的是 第一次搜索到的子串 到 父串尾部的 串, 然后拿到宽度
let finalString2 = String(i2String)
let size2_W = finalString2.size(withAttributes: [NSAttributedStringKey.font: labelFont]).width
if labelWidth > size.width { //这里要把最终字符串的宽度和 Label 的宽度进行比较, 才能确定显示的样式
messageLabel.attributedText = MessageDisplayTool.attriMessage(searchTxt: searchTxt, oriString: fatherString)
messageLabel.lineBreakMode = .byTruncatingTail
} else {
if size2_W < labelWidth { //如果子串的宽度小于 Label 宽度,就显示父串
messageLabel.attributedText = MessageDisplayTool.attriMessage(searchTxt: searchTxt, oriString: fatherString)
} else { //如果子串的宽度大于 Label 宽度,就显示子串, 这个子串是截取后的
messageLabel.attributedText = MessageDisplayTool.attriMessage(searchTxt: searchTxt, oriString: "\(finalString)...")
}
messageLabel.lineBreakMode = .byTruncatingHead
}
}
/// 添加富文本高亮
static func attriMessage(searchTxt: String, oriString: String) -> NSAttributedString {
let attri: NSAttributedString = NSAttributedString(string: oriString)
let newAttri = attri.applying(attributes: [NSAttributedStringKey.foregroundColor: UIColor.red], toOccurrencesOf: searchTxt)
return newAttri;
}
}
网友评论