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---------------------------------------------