ios - collectionView.collectionViewLayout.invalidateLayout()
问题描述
我在 TableView 中有一个动态 collectionView 并且添加时出现错误invalidateLayout
(图片如下)但是如果我删除invalidateLayout
前四个单元格被隐藏并且布局无法正确显示,则视频
请帮助我搜索了整个堆栈,但没有任何帮助谢谢
如果您需要测试项目
主视图控制器
class ViewController: UIViewController, UIScrollViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
setting()
}
func setting(){
getData()
tableView.dataSource = self
tableView.delegate = self
tableView.estimatedRowHeight = UITableView.automaticDimension
tableView.rowHeight = UITableView.automaticDimension
}
//load data
func pagination(_ completion: (()->())?){
SmartNetworkSevrice.getGoods(with: url) { [unowned self] (data) in
guard data.modals.count > 0 else {
self.tableView.tableFooterView = nil
return
}
self.goods.append(contentsOf: data.modals)
self.offSet += data.modals.count
DispatchQueue.main.async {
let indexPath = IndexPath(row: 0, section: 0)
self.tableView.tableFooterView = nil
if self.goods.count == data.modals.count || self.isRefresh {
self.tableView.reloadRows(at: [indexPath], with: .none)
} else {
if let cell = self.tableView.cellForRow(at: indexPath) as? TVCellGoods {
UIView.performWithoutAnimation {
self.tableView.beginUpdates()
cell.insertGoods(data.modals)
cell.layoutIfNeeded()
cell.collectionViewHeight.constant = cell.collectionView.collectionViewLayout.collectionViewContentSize.height
self.tableView.endUpdates()
}
}
}
completion?()
}
}
// define bottom of tableView
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard scrollView == self.tableView else { return }
if (!isMoreDataLoading) {
// Вычислить позицию длины экрана до нижней части результатов
let scrollViewContentHeight = scrollView.contentSize.height
let scrollOffsetThreshold = scrollViewContentHeight - scrollView.bounds.size.height
if(scrollView.contentOffset.y > scrollOffsetThreshold && scrollView.isDragging) {
isMoreDataLoading = true
self.tableView.isScrollEnabled = false;
self.tableView.isScrollEnabled = true;
pagination(nil)
}
}
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "goods", for: indexPath) as? TVCellGoods else { return UITableViewCell() }
guard bestGoods.count != 0, goods.count != 0 else { return UITableViewCell() }
cell.delegate = self
cell.configure(bestGoods, goods, categories)
// автообновление высоты
self.tableView.beginUpdates()
cell.collectionViewHeight.constant = cell.collectionView.collectionViewLayout.collectionViewContentSize.height
self.tableView.endUpdates()
return cell
}
}
extension ViewController: UITableViewDelegate, CallDelegate {
func callMethod() {}
func callMethod(push vc:UIViewController) {
self.navigationController?.pushViewController(vc, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
TableViewCell 与 collectionView
class TVCellGoods: UITableViewCell {
@IBOutlet weak var collectionView:UICollectionView!
@IBOutlet weak var collectionViewHeight:NSLayoutConstraint!
weak var delegate:CallDelegate?
var bestGoods = [Goods]() // лучшие товары
var goods = [Goods]() // все товары
var categories = [Menu]()
override func layoutSubviews() {
super.layoutSubviews()
self.collectionView.collectionViewLayout.invalidateLayout()
}
override func awakeFromNib() {
super.awakeFromNib()
collectionView.delegate = self
collectionView.dataSource = self
collectionView.tag = 2
collectionView.isScrollEnabled = false
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func configure(_ best:[Goods],_ goods:[Goods], _ category:[Menu]) {
self.bestGoods = best
self.goods = goods
self.categories = category
self.collectionView.reloadData()
}
func insertGoods(_ data:[Goods]) {
self.goods.append(contentsOf: data)
let count = self.bestGoods.count + self.categories.count + self.goods.count
let indexPaths = ((count - data.count) ..< count)
.map { IndexPath(row: $0, section: 0) }
self.collectionView.performBatchUpdates({
self.collectionView.insertItems(at: indexPaths)
}, completion: nil)
}
}
和 CollectionViewCell
class CVCellGoods: UICollectionViewCell {
@IBOutlet weak var bgView: UIView!
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var title: UILabel!
@IBOutlet weak var price: UILabel!
@IBOutlet weak var delivery: UIImageView!
@IBOutlet weak var premium: UIImageView!
override func prepareForReuse() {
super.prepareForReuse()
delivery.image = nil
premium.image = nil
title.text = nil
price.text = nil
imageView.image = nil
imageView.sd_cancelCurrentImageLoad()
}
override func awakeFromNib() {
super.awakeFromNib()
imageView.backgroundColor = UIColor(red: 215/255, green: 215/255, blue: 215/255, alpha: 1)
self.contentView.layer.cornerRadius = 5
self.contentView.layer.masksToBounds = true
self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOffset = CGSize(width: 0, height: 0.5)
self.layer.shadowRadius = 1
self.layer.shadowOpacity = 0.3
self.layer.masksToBounds = false
self.layer.shouldRasterize = true
self.layer.rasterizationScale = UIScreen.main.scale
}
}
编辑
如果我使用
self.collectionView.performBatchUpdates({
self.collectionView.insertItems(at: indexPaths)
}, completion: { _ in
self.collectionView.reloadItems(at: indexPaths)
})
然后我在invalidateLayout
屏幕底部得到一个空白空间
但是如果我删除invalidateLayout
我得到错误的布局
如果你没有像我一样的,那么就放弃你的改进项目
第二编辑
我注意到 iPhone 11 Pro 上有一个凹痕,而 iPhone 11 Pro Max 上一切正常
解决方案
更新:我验证了这适用于 iPhone SE、11 和 11 Max 的模拟器,在集合视图的末尾没有死区。
我的模拟器设置为暗模式,以显示集合视图的底部足以容纳加载图标。
我必须对此进行一些更改才能正确调整大小。首先,我在类中更改了您的insertGoods
函数,TVCellGoods
以便在插入后仅重新加载新添加的项目,并且列表顶部不再缺少项目:
self.collectionView.performBatchUpdates({
self.collectionView.insertItems(at: indexPaths)
}, completion: { _ in
self.collectionView.reloadItems(at: indexPaths)
})
一个大问题是为您的 tableView 单元格设置估计的行高。我已经删除了estimatedHeightForRowAt
覆盖并将您的替换heightForRowAt
为:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0 {
return (tableView.frame.width / 2.5) + 20
} else if indexPath.row == 1 {
return 70
} else {
guard let cell = tableView.cellForRow(at: indexPath) as? TVCellGoods else { return UITableView.automaticDimension }
// print(cell.collectionViewHeight.constant)
return cell.collectionViewHeight.constant
}
}
我还必须layoutIfNeeded
在您的ViewController UITableViewDataSource
扩展中添加到您的 cellForRow :
self.tableView.beginUpdates()
cell.collectionViewHeight.constant = cell.collectionView.collectionViewLayout.collectionViewContentSize.height
self.tableView.endUpdates()
cell.collectionView.layoutIfNeeded()
self.tableView.layoutIfNeeded()
最后,在使布局无效后,我必须更新您layoutSubviews
以分配正确的高度TVCellGoods
:
override func layoutSubviews() {
super.layoutSubviews()
self.collectionView.collectionViewLayout.invalidateLayout()
self.collectionViewHeight.constant = self.collectionView.collectionViewLayout.collectionViewContentSize.height
}
这是更新的源代码:https ://drive.google.com/open?id=1ldr4Ml2prZKmr1C4i1s5Sg7LvvxL7-jO
推荐阅读
- mysql-8.0 - 哪个版本的 OroCRM 适用于 oro:migration:load?
- mongodb - 我需要一遍又一遍地连接到 Mongo 吗?
- try-catch - java捕获indexoutofbounds异常
- javascript - 在 Vuex 中存储 Fabric.js 画布引用 - [vuex] 不会在突变处理程序之外改变 vuex 存储状态
- oracle - 如何从 refcursor 中选择
- c - 捕获 SIGCHLD 并替换终止的孩子
- android - 使用导航组件从一个活动导航到另一个活动
- html - Vue js 中的视频不以全宽和高度显示
- java - 在 Java 中,如何从字节数组中读取 n 位?
- c++ - C++中的函数重载和继承