14- 首页完善

2016-05-29  本文已影响74人  月下独酌灬

首页完善

实现功能

首页表情显示

步骤

  1. 将微博内容字符串生成一个 NSMutableAttributedString

代码实现

private func dealStatusText(statusText: String?) -> NSMutableAttributedString? {
    return nil
}
private func dealStatusText(statusText: String?) -> NSMutableAttributedString? {
    // 匹配表情字符串
    guard let text = statusText as NSString? else {
        return nil
    }

    /**
        第一个参数:正则表达式
        第二个参数:闭包,其参数:
            captureCount: 捕获个数
            captureString: 捕获的 String,指针
            captureRange: 捕获的 范围,指针
            stop: 是否停止捕获,指针
    */
    text.enumerateStringsMatchedByRegex("\\[[a-zA-Z0-9\\u4e00-\\u9fa5]+\\]") { (captureCount, captureString, captureRange, stop) -> Void in
        printLog(captureString.memory)
    }
    return nil
}
/// 一些计算的逻辑
private func setStatus(){
    ...
    dealStatusText(status?.text)
}
class HMMatchResult: NSObject {

    var captureString: String?
    var captureRange: NSRange?

    init(captureString: String, captureRange: NSRange) {
        self.captureRange = captureRange
        self.captureString = captureString
        super.init()
    }

}
// 利用数组保存匹配结果
var matchResults = [HMMatchResult]()

text.enumerateStringsMatchedByRegex("\\[[a-zA-Z0-9\\u4e00-\\u9fa5]+\\]") { (captureCount, captureString, captureRange, stop) -> Void in
    printLog(captureString.memory)

    let matchResult = HMMatchResult(captureString: captureString.memory! as String, captureRange: captureRange.memory)
    matchResults.append(matchResult)
}
/// 通过表情描述文字查找到对应有表情
///
/// - parameter chs: 表情描述文字
///
/// - returns: 表情模型
func emoticonWithChs(chs: String) -> HMEmoticon? {

    for emoticon in defaultEmoticons {
        if emoticon.chs == chs {
            return emoticon
        }
    }
    for emoticon in lxhEmoticons {
        if emoticon.chs == chs {
            return emoticon
        }
    }
    return nil
}
private func dealStatusText(statusText: String?) -> NSMutableAttributedString? {
    // 匹配表情字符串
    guard let text = statusText as NSString? else {
        return nil
    }
    // 将内容转成富文本
    let result = NSMutableAttributedString(string: text as String)

    // 利用数组保存匹配结果
    var matchResults = [HMMatchResult]()

    text.enumerateStringsMatchedByRegex("\\[[a-zA-Z0-9\\u4e00-\\u9fa5]+\\]") { (captureCount, captureString, captureRange, stop) -> Void in
        printLog(captureString.memory)

        let matchResult = HMMatchResult(captureString: captureString.memory! as String, captureRange: captureRange.memory)
        matchResults.append(matchResult)
    }


    // 反转遍历匹配结果
    // 为什么要返转遍历替换:原因就是如果从前往后替换的话会出现越界异常
    for matchResult in matchResults.reverse() {

        let emoticon = HMEmoticonTools.emoticonWithChs(matchResult.captureString! as String)

        if let emo = emoticon {
            // 通过表情模型生成 `NSAttributedString`
            // 通过表情模型初始化一个图片
            let image = UIImage(named: "\(emo.path!)/\(emo.png!)")
            // 初始化文字附件,设置图片
            let attatchment = HMEmoticonAttachment(chs: emo.chs!)
            attatchment.image = image
            // 图片宽高与文字的高度一样
            let imageWH = HMStatusContentFontSize
            // 调整图片大小 --> 解决图片大小以及偏移问题
            attatchment.bounds = CGRectMake(0, -4, imageWH, imageWH)

            // 通过文字附件初始化一个富文本
            let attributedString = NSMutableAttributedString(attributedString: NSAttributedString(attachment: attatchment))

            result.replaceCharactersInRange(matchResult.captureRange!, withAttributedString: attributedString)
        }
    }

    // 设置整个富文本的字体大小
    result.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(HMStatusContentFontSize), range: NSMakeRange(0, result.length))

    return result
}
/// 原创微博正文内容富文本
var originalStatusAttributedString: NSMutableAttributedString?


/// 一些计算的逻辑
private func setStatus(){
    // 来源字符串
    sourceText = dealSourceText(status?.source)
    originalStatusAttributedString = dealStatusText(status?.text)
}
/// 微博视图模型
var statusViewModel: HMStatusViewModel? {
    didSet{
        ...
        contentLabel.attributedText = statusViewModel?.originalStatusAttributedString
        ...
        }
    }
}

运行测试

var retweetStatusAttributedString: NSMutableAttributedString?


/// 一些计算的逻辑
private func setStatus(){
    // 来源字符串
    sourceText = dealSourceText(status?.source)
    originalStatusAttributedString = dealStatusText(status?.text)
    retweetStatusAttributedString = dealStatusText(retweetText)
}
/// 微博视图模型
var statusViewModel: HMStatusViewModel?{
    didSet{
        contentLabel.attributedText = statusViewModel!.retweetStatusAttributedString
        ...
    }
}

运行测试

特殊字符高亮显示

实现步骤:

代码实现

/// 给特殊字符添加颜色
///
/// - parameter attrString: 需要添加特殊字符高亮的富文本
private func addHighLightedAttr(attrString: NSMutableAttributedString) {

    // 匹配特殊字符串并高亮
}
private func dealStatusText(statusText: String?) -> NSMutableAttributedString? {
    ...

    // 添加特殊字符高亮
    addHighLightedAttr(result)

    // 设置整个富文本的字体大小
    result.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(HMStatusContentFontSize), range: NSMakeRange(0, result.length))

    return result
}
// 匹配 `@`
(attrString.string as NSString).enumerateStringsMatchedByRegex("@[^\\s^:^,]+") { (captureCount, captureString, captureRange, stop) -> Void in
    attrString.addAttribute(NSForegroundColorAttributeName, value: RGB(r: 80, g: 125, b: 175), range: captureRange.memory)
}
// 匹配 `#`
(attrString.string as NSString).enumerateStringsMatchedByRegex("#[^#]+#") { (captureCount, captureString, captureRange, stop) -> Void in
    attrString.addAttribute(NSForegroundColorAttributeName, value: RGB(r: 80, g: 125, b: 175), range: captureRange.memory)
}
// 匹配 `url`
(attrString.string as NSString).enumerateStringsMatchedByRegex("http(s)?://[^\\s^\\u4e00-\\u9fa5]+") { (captureCount, captureString, captureRange, stop) -> Void in
    attrString.addAttribute(NSForegroundColorAttributeName, value: RGB(r: 80, g: 125, b: 175), range: captureRange.memory)
}

特殊字符点击处理

实现思路

代码实现

class HMStatusLabel: UILabel {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupUI()
    }

    private func setupUI(){

    }
}

private lazy var contentLabel: HMStatusLabel = HMStatusLabel(textColor: UIColor.darkGrayColor(), fontSize: HMStatusContentFontSize, maxLayoutWidth: UIScreen.mainScreen().bounds.width - 2 * HMStatusCellMargin)
class HMStatusLabel: UILabel {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
        userInteractionEnabled = true;
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupUI()
    }

    private func setupUI(){
        addSubview(textView)
        textView.snp_makeConstraints { (make) -> Void in
            make.edges.equalTo(self)
        }
    }
    // MARK: - 懒加载控件
    private lazy var textView: UITextView = {
        let textView = UITextView()
        textView.alpha = 0.0
        return textView
    }()
}
override var attributedText: NSAttributedString? {
    didSet{
        textView.attributedText = attributedText
    }
}

运行测试:发现 textView 显示的内容与 label 显示的内容没有对齐,原因是 textView 里面的内容默认有一个间距

textView.textContainerInset = UIEdgeInsetsMake(0, -5, 0, -5)
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    let touch = touches.first!
    let location = touch.locationInView(self)
    print(location)
}
// 获取到用户点击对应的字符范围
let textRange = textView.characterRangeAtPoint(location)
textView.selectedTextRange = textRange
let range = textView.selectedRange
print(range)
// 转发微博匹配内容
var retweetMatchResults: [HMMatchResult]?
// 原创微博匹配内容
var originalMatchResults: [HMMatchResult]?
private func dealStatusText(statusText: String?) -> (attr: NSMutableAttributedString?, linkMatchResults: [HMMatchResult]?) {}
/// 添加高亮属性
///
/// - parameter attributedString:
private func addHighLightAttr(attributedString: NSMutableAttributedString) -> [HMMatchResult] {

    // 定义匹配结果数组
    var matchResult = [HMMatchResult]()


    // 匹配话题
    (attributedString.string as NSString).enumerateStringsMatchedByRegex("#[^#]+#") { (captureCount, caputureString, captureRange, stop) -> Void in
        attributedString.addAttribute(NSForegroundColorAttributeName, value: RGB(r: 80, g: 125, b: 175), range: captureRange.memory)
        // 保存匹配结果
        let result = HMMatchResult(captureString: caputureString.memory! as String, captureRange: captureRange.memory)
        matchResult.append(result)

    }
    ...
    // 返回结果
    return matchResult
}
let resultResult = dealStatusText(retweetText)
retweetStatusAttributedString = resultResult.attr
retweetMatchResults = resultResult.linkMatchResults
...
let originalResult = dealStatusText(status.text)
originalStatusAttributedString = originalResult.attr
originalMatchResults = originalResult.linkMatchResults
var linkMatchResult: [HMMatchResult]?
contentLabel.linkMatchResult = statusViewModel?.originalMatchResults
// 查看在哪一个 result 范围之内
for value in linkMatchResult! {
    // 当前用户点击的位置是特殊字符的位置
    if NSLocationInRange(range.location, value.captureRange) {
        print(value.captureString)

    }
}
textView.selectedRange = value.captureRange
// 根据 textView 取到当前用户点击的范围并添加 View
let rects = textView.selectionRectsForRange(textView.selectedTextRange!)
for rect in rects {
    let r = rect as! UITextSelectionRect
    let view = UIView(frame: r.rect)
    view.layer.cornerRadius = 5
    view.layer.masksToBounds = true
    view.backgroundColor = RGB(r: 177, g: 215, b: 255)
    self.insertSubview(view, atIndex: 0)
}

运行测试

lazy var linkSubView: [UIView] = [UIView]()
...
for rect in rects {
    ...
    self.insertSubview(view, atIndex: 0)
    linkSubView.append(view)
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    for value in linkSubView {
        value.removeFromSuperview()
    }
    linkSubView.removeAll()
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
    touchesEnded(touches!, withEvent: event)
}

运行测试

上一篇 下一篇

猜你喜欢

热点阅读