ios中UITableView鑲嵌UICollectionView正確設置高度及同時滑動

在tableview中嵌入collectionview時,如果沒有正確設置高度,會產生collectionview不能全部展現,只能在內部滑動的現象,這與預期是不符的。

解決思路:在內嵌的collectionView進行佈局的時候,拿到contentSize的高度h,然後在更新tableView cell的高度等於h.

兩種方案

  1. 不使用tableView自適應行高
  2. 使用AutoLayout配合tableView的自適應行高

1. 不使用tableView的自適應行高

思路

  • 在tableView cellForRow階段對cell中的collectionView reloadData,然後調用layoutIfNeeded()獲取到的contentSize,並記錄下這個高度h
  • cellForRowAt時,返回這個h就可以了.

需要注意

  • 不要在cellForRowAt中通過tableView獲取cell,然後拿cell的高度,其實你拿也拿不到,因爲這個時候cell還沒有顯示出來,tableView.cellForRow(at: indexPath)拿到的是nil,另外collectionView reloadData後,需要layoutIfNeeded才能正確拿到contentSize,因爲reloadData不是同步的,沒辦法同步拿到佈局.

關鍵代碼

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
	…
	cell.collectionView.data = someData
	cell.collectionView.reloadData()
	cell.collectionView.layoutIfNeeded()
	collectionCellHeight = cell.collectionvView.contentSize.height
	…
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
	…
	//if indexPath.row == collectionview所在cell的row
	return collectionCellHeight
	…
}

2. 使用tableView的自適應行高

思路

  • 首先啓用tableView的自動行高(ios 7還是8以後默認是啓用的)
  • 放置一個container在tableView cell的contentView上,collectionView放在container上;contentView的高度動態隨container變化,container高度隨collectionView變化
  • 當collection reload後立即layoutIfNeeded獲取contentSize,然後更新container的高度,由於是自動高度,因此tableView的cell也會調整到container的高度
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 44 // 設置一個和你的collectionView接近的值吧,默認44
class CustomCell: UITableViewCell {
    
    var dataArray: [String] = [] // 假定我們的數據結構就是一個String數組
    
    var collectionView: UICollectionView!
    
    var collectionContainer: UIView!
    
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        
        collectionContainer = UIView(frame: .zero)
        contentView.addSubview(collectionContainer)
        
        collectionContainer.mas_makeConstraints {
            $0?.left.equalTo()(self.contentView)
            // 這裏需要指定寬度,因爲collectionView佈局的時候,tableView的cell的frame還沒有正確設置還是estimate
            // 所以不可以這樣!
            // $0?.left.and()?.right()?.equalTo()(self.contentView)
            $0?.width.equalTo()(UIScreen.main.bounds.width)
            $0?.top.and()?.bottom()?.equalTo()(self.contentView) // container的上下邊和contentView一致,contentView會根據它的大小調整
            $0?.height.equalTo()(44) // 默認先隨便一個值吧,最好接近真實值,後面會update到真實值
        }
        
        let layout = UICollectionViewFlowLayout()
        layout.minimumLineSpacing = 10
        layout.minimumInteritemSpacing = 10
        layout.itemSize = CGSize(width: 50, height: 50)
        layout.scrollDirection = .vertical
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionContainer.addSubview(collectionView)
        
        collectionView.mas_makeConstraints {
            $0?.edges.equalTo()(self.collectionContainer)
        }
        
        collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "test")

        collectionView.delegate = self // 這裏根據具體業務寫吧,demo中我就把代理直接設置成cell了..
        collectionView.dataSource = self // 根據業務,demo直接先cell持有數據來控制collectionView的顯示了..
    }
    
    // 外部調用,用來設置collectionView的數據源
    func setData(_ data: [String]) {
        self.dataArray = data
        collectionView.reloadData()
        // 這裏需要 layoutIfNeeded 一下,否則我們不能同步拿到contentSize
        // 注意,如果上面collectionContainer的佈局沒有指明寬度,這個時候cell的寬度是estimate狀態,所以下面就算layout也拿不到正確的contentSize
        collectionView.layoutIfNeeded()

        let height = collectionView.contentSize.height
        
        collectionContainer.mas_updateConstraints { // 更新container的高度
            $0?.height.equalTo()(height)
        }
    }

}

需要注意

  • container需要指定寬度,否則拿到的是估算值,這個時候collectionView是他的子view,就算layoutIfNeeded也是以估算值來的,所以不不準確.

ps.

推薦一個自己寫的app:本人喜歡玩暴雪的遊戲,最近寫了一個暗黑破壞神3的遊戲工具,在裏面做了一些UI性能、流暢性的優化,感興趣的同學可以下載體驗下,順便給個評分~

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章