iOS 搜索文本在 UILabel 上的显示

前言

项目做了个搜索功能, 这个搜索功能有个很烦的显示样式, 这个样式竟然花了我两天的时间去搞定. 我才不是一个菜鸟程序猿

代码地址: https://github.com/gityuency/Autolayout

需求概述
  1. 在文本框里面输入文本, 将输入的字符和目标字符进行匹配, 把匹配到的结果显示在 Label 上, (其实就是使用一下网易云信的文本搜索功能,把搜索到的消息显示出来.)
  2. 如果这条消息很短, 那么, 在 Label 上完全显示, 这个没有问题.
  3. 如果这个消息很长, 那么 Label 是显示不全的, 这个时候, 要把匹配到的字符高亮显示出来.
  4. 如果匹配到的字符在目标字符串中间, 那么 Label 前后打上省略号.
  5. 如果匹配到的字符在目标字符串后面, 那么 Label 前面打上省略号.
  6. 如果匹配到的字符在目标字符串前面, 那么 Label 后面打上省略号.
  7. 如果目标字符串有多个子串被匹配到了, 那么取左边开始第一个匹配的到的子串并高亮.

我觉得作为一个程序猿, 上面的需求我写的很清晰.

效果图


iOS 搜索文本在 UILabel 上的显示_第1张图片
搜索.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[.. 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;
    }
    
}

你可能感兴趣的:(iOS 搜索文本在 UILabel 上的显示)