iOS UICollectionView estimatedItemSize 自定適應(yīng)高度(一)
效果圖
主要代碼在GATagFlowLayout里面币呵,還有代理計(jì)算高度。
如果需要展示其他類型cell 增加section分組的數(shù)量 然后在GATagFlowLayout計(jì)算寬高和位置熊响。注意最后的lastItemRect結(jié)果賦值。
import UIKit
class GATagCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var tagLabel: UILabel!
var model: String! {
didSet {
tagLabel.text = model
}
}
}
GATagCollectionViewCell.xib 如下圖
GATagCollectionViewCell.xib
//
// GATagCollectionViewController.swift
// YYFramework
//
// Created by 侯佳男 on 2018/12/28.
// Copyright ? 2018年 houjianan. All rights reserved.
//
import UIKit
class GATagCollectionViewController: YYBaseCollectionViewController {
lazy var layout: GATagFlowLayout = {
let l = GATagFlowLayout()
l.flowEdgeInset = UIEdgeInsets(top: 20, left: 10, bottom: 15, right: 10)
l.columSpace = 10
l.rowSpaces = [10]
l.delegate = self
return l
}()
override func viewDidLoad() {
super.viewDidLoad()
dataSource = ["123123", "123123", "2312123312312312123123123123123121231231231231231212312312312312312123123123123123121231231231231231212312312312312312123123123123123121231231231231231", "12", "1231212312312312312312123123123123123121231231231231231212312312312312312123123123123123121231231231231231212312312312312312123123123123123", "12312312312123123123123123121231231231231231212312312312312312123123123123123121231231231231231212312312312312312123123123123123121231231231231231212312312312312312123312312312123123123123123121231231231231231212312312312312312123123123123123121231231231231231212312312312312312123123123123123121231231231231231212312300", "123123123", "1231123123123123123121231231231231231212331231231212323123", "123123123", "123123123", "123123123", "123123", "2312123312312312123123123123123121231231231231231212312312312312312123123123123123121231231231231231212312312312312312123123123123123121231231231231231", "12", "1231212312312312312312123123123123123121231231231231231212312312312312312123123123123123121231231231231231212312312312312312123123123123123", "12312312312123123123123123121231231231231231212312312312312312123123123123123121231231231231231212312312312312312123123123123123121231231231231231212312312312312312123312312312123123123123123121231231231231231212312312312312312123123123123123121231231231231231212312312312312312123123123123123121231231231231231212312300", "123123123", "1231123123123123123121231231231231231212331231231212323123", "123123123", "123123123", "123123123"]
}
override func base_initCollectionViews() {
super.base_initCollectionViews()
collectionView.collectionViewLayout = layout
collectionView.yy_register(nibName: GATagCollectionViewCell.identifier)
}
func stringSize(s: String) -> CGSize {
if s.count == 0 {
return CGSize.zero
}
let font = UIFont.systemFont(ofSize: 14)
let width = UIScreen.main.bounds.size.width - self.layout.flowEdgeInset.left - self.layout.flowEdgeInset.right
let contentSize = (s as NSString).boundingRect(with: CGSize(width: width, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : font], context: nil).size
// 30是label距離左右的間距和 // 20距離上下和
let size = CGSize(width: min(contentSize.width + 30 + 2, width + 2), height: max(28, contentSize.height + 20))
return size
}
}
extension GATagCollectionViewController {
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: GATagCollectionViewCell.identifier, for: indexPath) as! GATagCollectionViewCell
cell.tagLabel.text = dataSource[indexPath.row] as? String
return cell
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataSource.count
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
}
extension GATagCollectionViewController: GATagFlowLayoutDelegate {
func tag(layout: GATagFlowLayout, indexPath: IndexPath) -> CGSize {
return stringSize(s: dataSource[indexPath.row] as! String)
}
}
//
// GATagFlowLayout.swift
// YYFramework
//
// Created by 侯佳男 on 2018/12/28.
// Copyright ? 2018年 houjianan. All rights reserved.
//
/*
func stringSize(s: String) -> CGSize {
if s.count == 0 {
return CGSize.zero
}
let font = UIFont.systemFont(ofSize: 14)
let width = UIScreen.main.bounds.size.width - self.layout.flowEdgeInset.left - self.layout.flowEdgeInset.right
let contentSize = (s as NSString).boundingRect(with: CGSize(width: width, height: CGFloat(MAXFLOAT)), options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : font], context: nil).size
// 32是label距離左右的間距和 // 20距離上下和
let size = CGSize(width: min(contentSize.width + 32, width + 2), height: max(28, contentSize.height + 25))
return size
}
*/
/*
lazy var layout: GATagFlowLayout = {
let l = GATagFlowLayout()
l.flowEdgeInset = UIEdgeInsets(top: 20, left: 30, bottom: 15, right: 40)
l.columSpace = 10
l.delegate = self
return l
}()
*/
import UIKit
protocol GATagFlowLayoutDelegate: class {
func tag(layout: GATagFlowLayout, indexPath: IndexPath) -> CGSize
}
class GATagFlowLayout: UICollectionViewFlowLayout {
weak var delegate: GATagFlowLayoutDelegate?
var columSpace: CGFloat = 0
var rowSpaces: [CGFloat] = [0] // 第一組
var sectionHeight: CGFloat = 0
var sectionTopSpace: CGFloat = 0
var flowEdgeInset: UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
var attrsArray: [UICollectionViewLayoutAttributes] = []
var sectionAttrsArray: [UICollectionViewLayoutAttributes] = []
private var lastItemRect: CGRect!
override init() {
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func initData() {
attrsArray.removeAll()
self.lastItemRect = CGRect(x: flowEdgeInset.left, y: flowEdgeInset.top, width: 0, height: 0)
}
override func prepare() {
super.prepare()
initData()
let sectionCount = collectionView!.numberOfSections
for j in 0..<sectionCount {
let attribute = layoutAttributesForSupplementaryView(ofKind: UICollectionElementKindSectionHeader, at: IndexPath(item: 0, section: j))
attrsArray.append(attribute!)
for i in 0..<collectionView!.numberOfItems(inSection: j) {
let attribute = layoutAttributesForItem(at: IndexPath(item: i, section: j))
attrsArray.append(attribute!)
}
}
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attribute = UICollectionViewLayoutAttributes(forCellWith: indexPath)
var orx: CGFloat = 0
var ory: CGFloat = 0
var isRowDs: CGFloat = 0
var isColumnDs: CGFloat = 0
if lastItemRect.maxX != flowEdgeInset.left {
isColumnDs = columSpace
}
if lastItemRect.maxY != flowEdgeInset.top {
isRowDs = rowSpaces[indexPath.section]
}
let size = delegate?.tag(layout: self, indexPath: indexPath)
let maxDistance = self.collectionView!.frame.size.width - self.lastItemRect.maxX - isColumnDs - self.flowEdgeInset.right
if size!.width > maxDistance {
orx = self.flowEdgeInset.left
ory = self.lastItemRect.origin.y + self.lastItemRect.size.height + isRowDs
} else {
orx = self.lastItemRect.origin.x + self.lastItemRect.size.width + isColumnDs
ory = self.lastItemRect.origin.y
}
attribute.frame = CGRect(x: orx, y: ory, width: size!.width, height: size!.height)
lastItemRect = attribute.frame
return attribute
}
override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attribute = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: elementKind, with: indexPath)
let x: CGFloat = 0
let y: CGFloat = lastItemRect.maxY + (indexPath.section != 0 ? sectionTopSpace : 0)
let w: CGFloat = collectionView!.width
let h: CGFloat = sectionHeight
attribute.frame = CGRect(x: x, y: y, width: w, height: h)
lastItemRect = attribute.frame
return attribute
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
return attrsArray
}
override var collectionViewContentSize: CGSize {
let maxContentHeight = lastItemRect.origin.y + lastItemRect.size.height + flowEdgeInset.bottom
return CGSize(width: 0, height: maxContentHeight)
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}