1、自定义EqualSpaceFlowLayout.swift
import UIKit
protocol EqualSpaceFlowLayoutDelegate: UICollectionViewDelegateFlowLayout {
func getContentHeight(height: CGFloat)
}
class EqualSpaceFlowLayout: UICollectionViewFlowLayout {
weak var delegate:EqualSpaceFlowLayoutDelegate?
var itemAttributes = [UICollectionViewLayoutAttributes]()
override init() {
super.init()
self.scrollDirection = .vertical
self.minimumLineSpacing = 10
self.minimumInteritemSpacing = 10
self.sectionInset = UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 0)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepare() {
super.prepare()
let itemCount: Int = self.collectionView?.numberOfItems(inSection: 0) ?? 0
var xOffset: CGFloat = self.sectionInset.left
var yOffset: CGFloat = self.sectionInset.top
var xNextOffset: CGFloat = self.sectionInset.left
for idx in 0..<itemCount {
let indexPath = NSIndexPath.init(item: idx, section: 0)
let itemSize = self.delegate?.collectionView?(self.collectionView ?? UICollectionView(), layout: self, sizeForItemAt: indexPath as IndexPath)
let itemW = (itemSize?.width ?? 0)
let itemH = (itemSize?.height ?? 0)
xNextOffset += self.minimumInteritemSpacing + itemW
if xNextOffset > (self.collectionView?.bounds.size.width ?? 0) - self.sectionInset.right {
xOffset = self.sectionInset.left
xNextOffset = self.sectionInset.left + self.minimumInteritemSpacing + itemW
yOffset += itemH + self.minimumLineSpacing
} else {
xOffset = xNextOffset - (self.minimumInteritemSpacing + itemW)
}
if idx == itemCount - 1 {
delegate?.getContentHeight(height: yOffset + itemH + minimumLineSpacing )
}
let layoutAttributes = UICollectionViewLayoutAttributes.init(forCellWith: indexPath as IndexPath)
layoutAttributes.frame = CGRect(x: xOffset, y: yOffset, width: itemW, height: itemH)
self.itemAttributes.append(layoutAttributes)
}
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return self.itemAttributes[indexPath.item]
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
return self.itemAttributes.filter { (evaluatedObject) -> Bool in
return rect.intersects(evaluatedObject.frame);
}
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
override func invalidateLayout() {
super.invalidateLayout()
self.itemAttributes.removeAll()
}
}
2.UIcollectionView中的实现
typealias AfterSaleSecondSelectViewClosure = (_ category: [AfterSaleSecondReasonModel]) -> Void
class AfterSaleSecondSelectView: UIView, EqualSpaceFlowLayoutDelegate {
func getContentHeight(height: CGFloat) {
self.contentH = height
}
@objc var selectedClosure: AfterSaleSecondSelectViewClosure?
@objc var selectCategory = [AfterSaleSecondReasonModel]()
@objc var categories = [AfterSaleSecondReasonModel]()
var contentH: CGFloat = 1
override init(frame: CGRect) {
super.init(frame: frame)
self.setupSubviews()
self.setupLayouts()
self.categoriesView.dataSource = self
self.categoriesView.delegate = self
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc func getContentHeight() -> CGFloat {
return self.contentH + 15
}
@objc func reloadData() {
self.selectCategory.removeAll()
self.categoriesView.reloadData()
self.categoriesView.collectionViewLayout.invalidateLayout()
}
// MARK: - subviews
private func setupSubviews() {
categoriesView.delegate = self
categoriesView.dataSource = self
self.addSubview(categoriesView)
self.addSubview(devideLine)
}
private func setupLayouts() {
categoriesView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
devideLine.snp.makeConstraints { (make) in
make.bottom.equalToSuperview()
make.left.equalToSuperview().offset(15)
make.right.equalToSuperview().offset(0)
make.height.equalTo(OnePixelHeight())
}
}
private var itemSize = CGSize(width: 70.0, height: 28.0)
lazy var categoriesView: UICollectionView = {
let flowLayout = EqualSpaceFlowLayout()
flowLayout.delegate = self
let tagsView = UICollectionView(frame: CGRect(x: 0, y: 0, width: kScreenWidth, height: 100), collectionViewLayout: flowLayout)
tagsView.isScrollEnabled = false
tagsView.backgroundColor = UIColor.white
tagsView.showsHorizontalScrollIndicator = false
tagsView.showsVerticalScrollIndicator = false
tagsView.contentInset = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5) // 20 是为了右边的渐变色
tagsView.register(cellType: AfterSaleSecondSelectCell.self)
tagsView.isUserInteractionEnabled = true
return tagsView
}()
private let devideLine = UIView().then {
$0.backgroundColor = RGBA_COLOR_HEX(hex: 0xEEEEEE)
}
}
extension AfterSaleSecondSelectView: UICollectionViewDataSource ,UICollectionViewDelegateFlowLayout {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.categories.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(for: indexPath, cellType: AfterSaleSecondSelectCell.self)
let item = self.categories[indexPath.row]
cell.titleLabel.text = item.value
if item.isSelect {
cell.contentView.layer.borderColor = COLOR_LIGHT_GREEN.cgColor
cell.titleLabel.textColor = COLOR_LIGHT_GREEN
cell.contentView.backgroundColor = RGBA_COLOR_HEX(hex: 0xFAFFFC, alpha: 1)
} else {
cell.contentView.layer.borderColor = COLOR_GRAY_BORDER.cgColor
cell.titleLabel.textColor = COLOR_SYSTEM_Normal_Black
cell.contentView.backgroundColor = .white
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let item = self.categories[indexPath.row]
if !item.isSelect {
let pointParam = BuriedParam()
pointParam.pageName = "refundPage"
pointParam.moduleName = "refund_reason_pop"
pointParam.objectName = "second_reason"
pointParam.setParametersWithKey("refund_first_reason", value: item.value)
pointParam.setParametersWithKey("name", value: item.value)
UserTrackingOperator.addEvent(with: pointParam, eventType: .click)
if self.selectCategory.count > 19 {
NeighborUtil.showMessage("标签选择已达上限")
return
}
}
item.isSelect = !item.isSelect
if item.isSelect {
self.selectCategory.append(item)
} else {
self.selectCategory = self.selectCategory.filter({$0 != item})
}
self.categoriesView.reloadData()
self.selectedClosure?(self.selectCategory)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let item = self.categories[indexPath.row]
let item_width = item.value?.boundingRect(with: CGSize.init(width: kScreenWidth - 120, height: 28), options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: [NSAttributedString.Key.font: UIFont.dd_boldFont(ofSize: 13)], context: nil).width ?? 60
let item_size: CGSize = CGSize(width: item_width + 20, height: 28)
return item_size
}
}
3、标签cell
class AfterSaleSecondSelectCell: BaseCollectionViewCell {
var isChoosed = false
override init(frame: CGRect) {
super.init(frame: frame)
self.contentView.addSubview(self.titleLabel)
titleLabel.snp.makeConstraints { (make) in
make.top.bottom.equalToSuperview()
make.left.equalToSuperview().offset(10)
make.right.equalToSuperview().offset(-10)
}
self.contentView.layer.cornerRadius = 14
self.contentView.layer.borderWidth = OnePixelHeight()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepareForReuse() {
super.prepareForReuse()
}
let titleLabel: UILabel = {
let l = UILabel()
l.backgroundColor = UIColor.clear
l.textColor = COLOR_SYSTEM_Normal_Black
l.font = UIFont.dd_font(ofSize: 12)
l.textAlignment = .center
l.numberOfLines = 1
l.isUserInteractionEnabled = true
return l
}()
}
核心就是1.自定义UICollectionViewFlowLayout
2.用自定义的UICollectionViewFlowLayout创建UIcollectionView