动态高度的CollectionView,支持tableView内嵌

可以扩展的collectionView1.gif
  • 对tableview,基本没有代码侵入,不会影响到你的任何操作,不过,需要你的tableview,行高自适应

实现思路

  1. 根据flowLayout以及数据源的count来确定collectionView的Height。
  2. 根据每行最多展示数,以及未展最多展示数,来确定collectionView展示函数,以确定collectionView的Height。
  3. 点击展开后,把数据源count显示到最大。并且,改变collectionView的Height。
  4. tableView的复用问题,给tableView添加字典属性,并且把indexPath作为key,记录当前是否为展开状态。
  5. 自定义tableViewCell,来配置collectionView的flowLayout,以及一些其他的属性

主要的类

一、PYElasticityCollectionView:UIView

  1. 这个里面主要包含一个collectionView,和一个Button。
  2. 管理了collectionView的Height,以及collectionView与Button的布局问题

初始化方法:
需要一个collectionView的layout,以及collectionView的Button

 init(frame: CGRect, cellClass: AnyClass, layout: UICollectionViewFlowLayout) 

必须设置这个值,在你的tableview数据源中

 var indexPath: IndexPath?

数据源

modelArray: [Any] = []

展示控制

   ///未展开的时候最多展示多少条
    var maxShowItem: NSInteger = 0
    ///每一行有多少
    var maxRowItemNum: NSInteger = 1

高度

    ///当前这个view的高度
    var currentViewH: CGFloat 
    ///当前的 collectionView的高度
    var currentCollectionViewH: CGFloat

二、PYElasticityTableViewCell

为了配合tableView做的封装

里面包含bottomView和topView,自管理collectionView的展开与收起

点击后展开按钮后,父控件是否自动刷新数据(默认是true,如果设置成False,请在tableview中的数据源中用receivedSignalFunc函数监听点击事件,然后自行刷新,注意signalKey为PYElasticityTableViewCell_ClickMoreButton)

 var isAutoReloadData: Bool = true

update topViewH,如果在创建self的时候,没有给topViewH,那么请不要用这个来更改topView的高度

  var topViewH: CGFloat? = 0 

upDate topViewH, 如果在创建self的时候,没有给bottomViewH,那么请不要用这个来更改bottomView的高度

 var bottomViewH: CGFloat? = 0

collectionView的Button

var collectionViewBottomButton

配置cell,使得里面有点击按钮可以伸缩的collectionView,《🌶topView与bottomView,自适应🌶》

func configurationCollectionViwFunc(layout: UICollectionViewFlowLayout,cellClass: AnyClass,maxShowItem: NSInteger, maxRowItemNum: NSInteger,isHiddenButton: Bool? = false,buttonInstert: UIEdgeInsets? = UIEdgeInsetsMake(0, 0, 0, 0),topView: PYElasticityTopView? = nil, bottomView: PYElasticityBottomView? = nil)

配置cell,使得里面有点击按钮可以伸缩的collectionView,《🌶topView与bottomView需要固定高度,不能自适应🌶》

func configurationCollectionViwFunc(layout: UICollectionViewFlowLayout,cellClass: AnyClass,maxShowItem: NSInteger, maxRowItemNum: NSInteger,isHiddenButton: Bool? = false,buttonInstert: UIEdgeInsets? = UIEdgeInsetsMake(0, 0, 0, 0),topView: PYElasticityTopView? = nil, bottomView: PYElasticityBottomView? = nil,topViewH: CGFloat? = 0, bottomViewH: CGFloat? = 0)

用法PYElasticityTableViewCell

  1. 把tableview设置成自适应行高
  2. 继承自PYElasticityTableViewCell,然后自定义一个传输数据的model接口,
  3. 然后在model的didSet方法里面,你要调用setUPElasticityCollectionViewDataSourceFunc这个方法,给collectionView传递数据,
  4. 如果不想点击collectionView下面的按钮后自动让你的tableview刷新,那么可以设置属性isAutoReloadData为False,但是你必须要在tableVIew的数据源中,监听到点击事件,并手动刷新,直接复制粘贴下面代码到数据源中,注意message,是collectionView当前的数据源数组。
    注意,你要把cell的isAutoReloadData置位false否则tableView会刷新两次
  ///注意,这句话要写,不然会刷新两次cell.isAutoReloadData = false
  self?.eceivedSignalFunc(eventCallBack: { [weak self](signalKey, message) -> (Any)? in
            if signalKey == PYElasticityTableViewCell_ClickMoreButton {
                /// 你要的点击事件在这里拿到
                self?.reloadData()
            }
            return nil
        })

自适应行高

  //tableview的行高自适应,这个要尽量的接近你的自适应高度
        estimatedRowHeight = kViewCurrentH_XP(H: 500)
 //iOS8之后默认就是这个值,可以省略
       rowHeight = UITableViewAutomaticDimension

collectionViewCell 的分类

解决数据的传输 问题
在collectionViewCell中,调用 self.setUPDateSourceFunc block来接受数据

//MARK: - 为cell添加分类
extension UICollectionViewCell {
    var setUPDateSourceCallBack: ((_ model: Any)->())? {
        get {
            return objc_getAssociatedObject(self, UICollectionViewCell.struct_BaseUICollectionViewKey.k_CellDataSource) as? ((Any) -> ())
        }
        set (newValue) {
            objc_setAssociatedObject(self, UICollectionViewCell.struct_BaseUICollectionViewKey.k_CellDataSource, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
    }
    
    struct struct_BaseUICollectionViewKey {
        static let k_Cell = UnsafeRawPointer.init(bitPattern:"cell".hashValue)
        static let k_CellDataSource = UnsafeRawPointer.init(bitPattern:"k_CellDataSource".hashValue)
        static let k_CellIndexPath = UnsafeRawPointer.init(bitPattern:"k_CellIndexPath".hashValue)
    }
    var indexPath: NSIndexPath {
        get {
            return objc_getAssociatedObject(self, UICollectionViewCell.struct_BaseUICollectionViewKey.k_CellIndexPath) as! NSIndexPath
        }
        set (newValue) {
            setUPDateSourceCallBack?(newValue)
            objc_setAssociatedObject(self, UICollectionViewCell.struct_BaseUICollectionViewKey.k_CellIndexPath, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    var model_BaseData_: Any {
        get {
            return objc_getAssociatedObject(self, UICollectionViewCell.struct_BaseUICollectionViewKey.k_Cell)
        }
        set (newValue) {
            setUPDateSourceCallBack?(newValue)
            objc_setAssociatedObject(self, UICollectionViewCell.struct_BaseUICollectionViewKey.k_Cell, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    ///collectionViewCell 接受数据 的函数
    func setUPDateSourceFunc(_ setUPDateSourceCallBack: ((_ model: Any)->())?) {
        self.setUPDateSourceCallBack = setUPDateSourceCallBack
    }
}

代码示例

tableView代码示例
其实正常写就可以了

import UIKit

class PYTableView: UITableView,
UITableViewDelegate,
UITableViewDataSource
{
    override init(frame: CGRect, style: UITableViewStyle) {
        super.init(frame: frame, style: style)
        setUP()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    private func setUP() {
        self.dataSource = self
        self.delegate = self
        //tableview的行高自适应,这个要尽量的接近你的自适应高度
        estimatedRowHeight = kViewCurrentH_XP(H: 500)
        //iOS8之后默认就是这个值,可以省略
        rowHeight = UITableViewAutomaticDimension
        self.register(PYElasticityTestTCell.classForCoder(), forCellReuseIdentifier: "CELLID")
    }
}

extension PYTableView {
    ///数据原方法
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 12
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CELLID", for: indexPath) as! PYElasticityTestTCell
//        cell.isSelect = self.getCellIsSelected(index: indexPath)
        cell.indexPath = indexPath
        cell.modelArray = [
            "不","是","和","还",
        ]
        cell.selectionStyle = .none
        
        cell.backgroundColor = #colorLiteral(red: 0.8520416148, green: 0.9956474186, blue: 1, alpha: 1)
        
        //发送消息
        NSObject.stitchChannelFunc(sender: cell, receiver: self)
        return cell
    }
}

PYElasticityTestTCell: PYElasticityTableViewCell代码示例

class PYElasticityTestTCell: PYElasticityTableViewCell {
    let topView = PYTopViewTest()
    let bottomView = PYElasticityBottomView_Test()
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        self.configurationCollectionViwFunc(layout: self.layout, cellClass: PYCollectionViewCell.classForCoder(), maxShowItem: 2, maxRowItemNum: 2, isHiddenButton: false, topView: topView, bottomView: bottomView, topViewH: kViewCurrentH_XP(H: 100), bottomViewH: kViewCurrentH_XP(H: 100))
        self.setUPButton()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    private lazy var layout: UICollectionViewFlowLayout = {
        let layoutF = UICollectionViewFlowLayout()
        layoutF.itemSize = CGSize(width: kViewCurrentW_XP(W: 325), height: kViewCurrentW_XP(W: 202))
        layoutF.scrollDirection = .vertical
        layoutF.minimumLineSpacing = kViewCurrentW_XP(W: 40)
        layoutF.minimumInteritemSpacing = kViewCurrentW_XP(W: 30)
        layoutF.sectionInset = UIEdgeInsetsMake(kViewCurrentW_XP(W: 30), kViewCurrentW_XP(W: 30), 0, kViewCurrentW_XP(W: 30))
        return layoutF
    }()
    private func setUPButton() {
        //未完成数据展示的collectionView展示
       collectionViewBottomButton.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
        self.collectionViewBottomButton.setTitle("button", for: .normal)
        self.collectionViewBottomButton.titleLabel?.font = UIFont.kr_font(size: 26)
        self.collectionViewBottomButton.setTitle("更多", for: .normal)
        self.collectionViewBottomButton.setTitle("收起", for: .selected)
        collectionViewBottomButton.setTitleColor(UIColor.gray, for: .normal)
        collectionViewBottomButton.setTitleColor(UIColor.black, for: .selected)
        
        self.viewDispachDataReciveFunc {[weak self] (key, message) -> (Any)? in
            self?.topView.label.text = message as! String
        }
    }
    
    var modelArray: [Any]?{
        didSet {
            ///在这里可以对 top View 和 bottom view 的高度约束进行更改
            //            self.topViewH = 200
            //            self.bottomViewH = 300
            
            ///用这个方法来给collectionViewCell传递数据
            self.setCollectionViewData(data: modelArray ?? [])
        }
    }
}

collectionViewCell中 接受传输的数据的方法

  ///collectionViewCell 接受数据 的函数
    func setUPDateSourceFunc(_ setUPDateSourceCallBack: ((_ model: Any)->())?) {
        self.setUPDateSourceCallBack = setUPDateSourceCallBack
    }

更新 2018.4.10

  • 对代码进行了瘦身。
  • 修复了在通过对 self.topViewH赋值更新 topView (bottomView) height 约束的时候会出现莫名的bug

示例代码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,440评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,814评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,427评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,710评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,625评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,014评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,511评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,162评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,311评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,262评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,278评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,989评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,583评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,664评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,904评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,274评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,856评论 2 339

推荐阅读更多精彩内容