最近在写列表,列表内容默认显示2行,如果超过两行,则在内容结尾显示查看更多,点击查看更多,展开全部内容
日常搜索了一圈,发现很多实现的逻辑需要计算内容高度,然后根据高度去控制查看更多的显示,由于经历过高度计算各种小误差的坑,果断放弃了这种计算高度的方案,于是决定结合 BSText 自己封装一个 Label ,也方便后边使用
废话不多说,直接上代码
// MARK: 查看更多Label
class MoreLabel: BSLabel {
/// 点击查看更多闭包
var touchShowMoreBtnBlock: (() -> Void)?
/// 点击收起闭包
var touchPackupBtnBlock: (() -> Void)?
/// Label 内容
private var labelStr: String?
// MARK: 配置内容
/// 配置内容
/// - Parameters:
/// - labelStr: Label 内容
/// - isShowPackup: 是否显示收起 默认不显示 可根据自己需求判断是否显示
open func setContent(labelStr: String, isShowPackup: Bool = false) {
self.labelStr = labelStr
let attachText = NSMutableAttributedString.init(string: labelStr)
attachText.bs_lineSpacing = 4
attachText.bs_font = self.font
attachText.bs_color = self.textColor
self.attributedText = attachText
/// 是否显示收起按钮
if isShowPackup {
/// 添加收起按钮
self.addPackupButton()
}
}
// MARK: 添加查看更多按钮
open func addSeeMoreButton() {
let text = NSMutableAttributedString(string: "...查看全部")
let highlight = TextHighlight()
highlight.color = .mainThemeColor
highlight.tapAction = { [weak self] containerView, text, range, rect in
guard let strongSelf = self else { return }
strongSelf.touchShowMoreBtnBlock?()
}
/// 设置查看全部高亮颜色
text.bs_color = self.textColor
text.bs_set(color: .mainThemeColor,
range: ((text.string as NSString?)?.range(of: "查看全部"))!)
text.bs_set(textHighlight: highlight,
range: ((text.string as NSString?)?.range(of: "查看全部"))!)
text.bs_font = self.font
let seeMore = BSLabel()
seeMore.attributedText = text
seeMore.sizeToFit()
let truncationToken = NSAttributedString.bs_attachmentString(with: seeMore,
contentMode: UIView.ContentMode.center,
attachmentSize: seeMore.size,
alignTo: text.bs_font,
alignment: TextVerticalAlignment.center)
self.truncationToken = truncationToken
}
// MARK: 添加查看更多按钮
private func addPackupButton() {
let text = NSMutableAttributedString(string: " 收起")
let highlight = TextHighlight()
highlight.color = .mainThemeColor
highlight.tapAction = { [weak self] containerView, text, range, rect in
guard let strongSelf = self else { return }
strongSelf.touchPackupBtnBlock?()
}
/// 设置收起高亮颜色
text.bs_set(color: .mainThemeColor,
range: ((text.string as NSString?)?.range(of: "收起"))!)
text.bs_set(textHighlight: highlight,
range: ((text.string as NSString?)?.range(of: "收起"))!)
text.bs_font = self.font
let attachText: NSMutableAttributedString = NSMutableAttributedString.init(string: self.labelStr ?? "")
attachText.bs_font = self.font
attachText.bs_color = self.textColor
attachText.bs_lineSpacing = 4
attachText.append(text)
self.attributedText = attachText
}
/// 子视图超出本视图的部分也能接收事件
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if !self.isUserInteractionEnabled || self.isHidden || self.alpha <= 0.01 {
return nil
}
let resultView = super.hitTest(point, with: event)
if resultView != nil {
return resultView
} else {
for subView in self.subviews.reversed() {
// 这里根据层级的不同,需要遍历的次数可能不同,看需求来写,我写的例子是一层的
let convertPoint: CGPoint = subView.convert(point, from: self)
let hitView = subView.hitTest(convertPoint, with: event)
if hitView != nil {
return hitView
}
}
}
return nil
}
}
那么该如何使用呢???? 接着看,我这里是用 TableViewCell 加载
// MARK: 配置UI
override func configUI() {
self.contentView.addSubview(self. testLabel)
/// 这里用了 SnapKit
self.testLabel.snp.makeConstraints { make in
make.top.left.equalToSuperview().offset(margin)
make.bottom.right.equalToSuperview().offset(-margin)
}
}
private lazy var testLabel: MoreLabel = {
let label = MoreLabel()
label.textColor = .mainTextColor153
label.font = .systemFont10
/// 默认行数设置为2
label.numberOfLines = 2
/// 给个最大宽度
label.preferredMaxLayoutWidth = kScreenWidth-margin*2
label.textVerticalAlignment = TextVerticalAlignment.top
label.addSeeMoreButton()
label.touchShowMoreBtnBlock = { [weak self] in
guard let strongSelf = self else { return }
/// 点击了查看更多
strongSelf.isUnfold = true
}
label.touchPackupBtnBlock = { [weak self] in
guard let strongSelf = self else { return }
/// 点击了收起
strongSelf.isUnfold = false
}
return label
}()
/// 是否展开 true:展开 false:收起
var isUnfold: Bool? {
didSet {
guard let isUnfold = isUnfold else {
return
}
if isUnfold {
/// 设置行数为0
self.testLabel.numberOfLines = 0
} else {
/// 设置行数为2
self.testLabel.numberOfLines = 2
}
/// 设置要显示的内容
self. testLabel.setContent(labelStr: "我是测试内容我是测试内容我是测试内容我是测试内容我是测试内容我是测试内容我是测试内容我是测试内容", isShowPackup: isUnfold)
}
}
我这里是结合项目需求使用的,码友也可以根据自己需求做调整
大概就这么个流程
小小码工一枚,有写的不足的地方,就多做自我检讨吧