swift 标签2

 

 

 

// ------------------------------YPTextCollectionView----------------------------------------------

 

import UIKit

import RxRelay

 

/// 字符串自动宽度布局,比如标签等等

class YPTextCollectionView<T>: YPBaseView, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {

    // MARK: 非UI属性

    

    var datas: [InputData] = [] {

        didSet{

            collectionV?.reloadData()

        }

    }

    

    /// 用户选中事件

    let clickHandler: BehaviorRelay<OutputData?> = .init(value: nil)

    

    /// 字体

    var font: UIFont = 12.yp_font

    /// 正常颜色

    var normalColor: YPTextCollectionItemColorConfig = .init(textColor: .Other.b65, bgColor: .Background.f5f6fa)

    /// 正常颜色

    var selectedColor: YPTextCollectionItemColorConfig? = nil

    /// 背景圆角

    var bgCornerRadius: CGFloat = 2.scale

    /// 内容边距

    var padding: UIEdgeInsets = .init(top: 6.scale, left: 8.scale, bottom: 6.scale, right: 8.scale)

    /// 边框颜色

    var padColor: UIColor = .Background.e5f4ff

    /// 边框宽度

    var padW: CGFloat = 0

    fileprivate let layoutAlignment: YPCollectionViewFlowLayout.Alignment

    fileprivate let minL: CGFloat

    fileprivate let minInL: CGFloat

    fileprivate let edgetInset: UIEdgeInsets

    

    /// 选中的快捷输入

    private var selectLabels: [String] = []

    

    /// 将选中的快捷输入拼接成字符串

    private var quickInputs: String {

        var tmpStr: String = ""

        selectLabels.forEach { str in

            tmpStr += "|\(str)|"

        }

        return tmpStr

    }

    

    // MARK: UI属性

    

    fileprivate var layout: YPCollectionViewFlowLayout?

    

    fileprivate var collectionV: UICollectionView?

    

    // i选中风格

    private let selectStyleEnum: SelectedStyle

    

    // MARK: 系统方法

    init(alignment: YPCollectionViewFlowLayout.Alignment, min: CGFloat, minIL: CGFloat, inset: UIEdgeInsets, selectStyle: SelectedStyle = .none) {

        // isShouldSelect: 点击是否蓝色高亮

        self.selectStyleEnum = selectStyle

        layoutAlignment = alignment

        minL = min

        minInL = minIL

        edgetInset = inset

        super.init(frame: .zero)

        

        layout = YPCollectionViewFlowLayout(alignment: layoutAlignment,

                                            min: min,

                                            minIL: minInL,

                                            inset: edgetInset)

        layout?.scrollDirection = .vertical

        guard let l = layout else { return }

        collectionV = UICollectionView.init(frame: .zero, collectionViewLayout: l)

        collectionV?.backgroundColor = .clear

        collectionV?.delegate = self

        collectionV?.isScrollEnabled = false

        collectionV?.dataSource = self

        collectionV?.register(YPTextCollectionCell.classForCoder(),

                   forCellWithReuseIdentifier: NSStringFromClass(YPTextCollectionCell.classForCoder()))

        addSubview(collectionV!)

        collectionV?.snp.makeConstraints { make in

            make.edges.equalToSuperview()

        }

    }

    

    required init?(coder: NSCoder) {

        fatalError("init(coder:) has not been implemented")

    }

    

    override func layoutSubviews() {

        super.layoutSubviews()

        collectionV?.reloadData()

    }

    

    // MARK: 自定义公共方法

    

    func updateFrame(maxW: CGFloat) -> CGFloat {

        var currentW: CGFloat = 0

        var index: Int = 0

        let currentMaxW: CGFloat = maxW - edgetInset.left - edgetInset.right

        var cH: CGFloat = edgetInset.top

        var maxH: CGFloat = 0

        for _ in datas {

            let itemSize = itemSize(indexPath: .init(row: index, section: 0), frameWidth: currentMaxW)

            currentW += (itemSize.width + minL)

            index += 1

            /// 超过了最大宽度,换行

            if (currentW - minL) > currentMaxW {

                cH += (maxH + minInL)

                currentW = itemSize.width + minL

                maxH = 0

            }

            maxH = maxH < itemSize.height ? itemSize.height : maxH

        }

        /// 因为在换行后才会增加高度,所以需要添加第一行高度

        cH += (maxH + edgetInset.bottom)

        return cH

    }

    

    /// 限制行数

    /// - Parameters:

    ///   - maxW: 宽

    ///   - maxLine: 最大行

    /// - Returns: 高度

    func constrainLabelsHeightToTwoLineHeight(maxW: CGFloat,maxLine: Int) -> CGFloat {

        var lineNum: Int = 1

        var currentW: CGFloat = 0

        var index: Int = 0

        let currentMaxW: CGFloat = maxW - edgetInset.left - edgetInset.right

        var cH: CGFloat = edgetInset.top

        var maxH: CGFloat = 0

        for _ in datas {

            let itemSize = itemSize(indexPath: .init(row: index, section: 0), frameWidth: currentMaxW)

            currentW += (itemSize.width + minL)

            index += 1

            /// 超过了最大宽度,换行, 超过最大行不增加高度

            if (currentW - minL) > currentMaxW  {

                if lineNum <= maxLine {

                    cH += (maxH + minInL)

                }

                currentW = itemSize.width + minL

                maxH = 0

                lineNum = lineNum + 1

            }

            if lineNum <= maxLine {

                maxH = maxH < itemSize.height ? itemSize.height : maxH

            }

        }

        /// 因为在换行后才会增加高度,所以需要添加第一行高度

        cH += (maxH + edgetInset.bottom)

        return cH

    }

    

    /// item 大小计算

    fileprivate func itemSize(indexPath: IndexPath, frameWidth: CGFloat) -> CGSize{

        

        let lineH: CGFloat = font.lineHeight + padding.top + padding.bottom

        if datas.count > indexPath.row {

            let data = datas[indexPath.row]

            let pad = data.padding ?? padding

            let leftRightPadding = pad.left + pad.right

            let maxW = frameWidth - edgetInset.left - edgetInset.right - leftRightPadding

            let size = data.text.size(maxW: maxW, font: data.font ?? font, numberOfLines: 0)

            return .init(width: size.width + leftRightPadding, height: lineH)

        }

        return .init(width: padding.left + padding.right, height: lineH)

    }

    

    // MARK: uicollectionview delegate & datasource

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

        return itemSize(indexPath: indexPath, frameWidth: collectionView.frame.width)

    }

 

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

        return edgetInset

    }

 

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {

        return minL

    }

 

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {

        return minInL

    }

 

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

        return datas.count

    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(YPTextCollectionCell.classForCoder()), for: indexPath) as! YPTextCollectionCell

        if datas.count > indexPath.row {

            let d = datas[indexPath.row]

            cell.padColor = padColor

            cell.padW = padW

            var tmpData = YPTextCollectionCell.InputData.init(text: d.text,

                                                              font: d.font ?? font,

                                                              normalColor: d.normalColor ?? normalColor,

                                                              selectedColor: d.selectedColor ?? selectedColor,

                                                              bgCornerRadius: d.bgCornerRadius ?? bgCornerRadius,

                                                              padding: d.padding ?? padding,

                                                              isSelect: d.isSelect)

            // 给 textColor, bgColor 赋值

            if self.selectStyleEnum != .none {

                tmpData.isSelect = d.isSelect

            } else {

                tmpData.isSelect = false

            }

            cell.data = tmpData

        }

        return cell

    }

 

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        if datas.count > indexPath.row {

            datas[indexPath.row].isSelect = !datas[indexPath.row].isSelect

            let d = datas[indexPath.row]

            if datas[indexPath.row].isSelect {

                if selectStyleEnum == .signle {

                    self.selectLabels.removeAll(where: {$0 == d.text})

                }

                self.selectLabels.append(d.text)

            } else {

                self.selectLabels.removeAll(where: {$0 == d.text})

            }

            self.collectionV?.reloadData()

            clickHandler.accept(.init(text: d.text, index: indexPath, quickInputs: self.quickInputs, data: d.data))

        }

    }

}

 

extension YPTextCollectionView {

    

    struct OutputData {

        let text: String

        let index: IndexPath

        let quickInputs: String

        let data: T?

    }

    

    /// 选中风格

    enum SelectedStyle: String {

        /// 没有选中状态

        case none

        /// 单选

        case signle

        /// 多选

        case mutiple

    }

    

    /// 数据

    struct InputData {

        /// 字符串

        let text: String

        ///  数据

        let data: T?

        /// 字体

        let font: UIFont?

        /// 正常颜色

        let normalColor: YPTextCollectionItemColorConfig?

        /// 正常颜色

        var selectedColor: YPTextCollectionItemColorConfig?

        /// 背景圆角

        let bgCornerRadius: CGFloat?

        /// 内容边距

        let padding: UIEdgeInsets?

        /// 是否选中

        var isSelect: Bool = false

        

        init(text: String,

             data: T? = nil,

             font: UIFont? = nil,

             normalColor: YPTextCollectionItemColorConfig? = nil,

             selectedColor: YPTextCollectionItemColorConfig? = nil,

             bgCornerRadius: CGFloat? = nil,

             padding: UIEdgeInsets? = nil,

             isSelect: Bool = false){

            self.text = text

            self.data = data

            self.font = font

            self.normalColor = normalColor

            self.selectedColor = selectedColor

            self.bgCornerRadius = bgCornerRadius

            self.padding = padding

            self.isSelect = isSelect

        }

    }

    

}

// ------------------------------YPTextCollectionView----------------------------------------------

// -------------------------------YPTextCollectionCell---------------------------------------------

 

import UIKit

 

class YPTextCollectionCell: YPBaseCollectionViewCell {

    

    // MARK: 非UI属性

    var data: InputData? {

        didSet {

            configData()

        }

    }

    

    // MARK: UI属性

    

    fileprivate var cV: UIView = {

        let v = UIView()

        return v

    }()

    

    fileprivate lazy var titleL: UILabel = {

        let l = UILabel()

        l.textAlignment = .center

        return l

    }()

    /// 边框颜色

    var padColor: UIColor = .Background.e5f4ff

    /// 边框宽度

    var padW: CGFloat = 0

    

    // MARK: 系统方法

    

    // MARK: 自定义公共方法

    override func makeUI() {

        super.makeUI()

        backgroundColor = .clear

        backgroundView = UIView()

        backgroundView?.backgroundColor = .clear

        contentView.addSubview(cV)

        cV.addSubview(titleL)

        

        cV.snp.makeConstraints { make in

            make.edges.equalToSuperview()

        }

        configData()

    }

    

    func configData() {

        guard let inputData = data, let _ = titleL.superview else { return }

        titleL.text = inputData.text

        titleL.font = inputData.font

        

        let currentColor = inputData.isSelect ? (inputData.selectedColor ?? inputData.normalColor) : inputData.normalColor

        titleL.textColor = currentColor.textColor

        cV.backgroundColor = currentColor.bgColor

        cV.layer.cornerRadius = inputData.bgCornerRadius

        cV.layer.masksToBounds = true

        cV.layer.borderColor = padColor.cgColor

        cV.layer.borderWidth = padW

        

        titleL.snp.removeConstraints()

        titleL.snp.makeConstraints { make in

            make.left.equalTo(inputData.padding.left)

            make.right.equalTo(-inputData.padding.right)

            make.top.bottom.equalToSuperview()

        }

        

    }

    

}

 

extension YPTextCollectionCell {

    

    /// 数据

    struct InputData {

        /// 字符串

        let text: String

        /// 字体

        let font: UIFont

        /// 正常颜色

        let normalColor: YPTextCollectionItemColorConfig

        /// 正常颜色

        var selectedColor: YPTextCollectionItemColorConfig?

        /// 背景圆角

        let bgCornerRadius: CGFloat

        /// 内容边距

        let padding: UIEdgeInsets

        

        /// 是否选中

        var isSelect: Bool = false

    }

}

 

 

/// 选项卡颜色设置

struct YPTextCollectionItemColorConfig {

    /// 文字颜色

    var textColor: UIColor

    /// 背景色

    var bgColor: UIColor

}

// -------------------------------YPTextCollectionCell---------------------------------------------

 

posted @ 2022-04-07 17:36  super1250  阅读(52)  评论(0编辑  收藏  举报