移动时附加到 UICollectionView 中的单元格的弹出框被称为此集合视图的 ReloadData
Posted
技术标签:
【中文标题】移动时附加到 UICollectionView 中的单元格的弹出框被称为此集合视图的 ReloadData【英文标题】:Popover attached to cell in UICollectionView moving when is called the ReloadData of this collection view 【发布时间】:2020-02-14 13:40:02 【问题描述】:我有一个用户可以单击的 UICollectionView,它显示了一个附加到单击的单元格的弹出框。在 ios 12 中,无论是否调用了重新加载数据,弹出框都保持在同一原点(x、y 或单元格),但在 iOS 13 中,当调用集合视图的重新加载数据时,弹出框在单元格之间移动。
关注 iOS 13 中的行为视频: https://vimeo.com/385021234
演示是使用以下代码完成的:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
guard let cell = collectionView.cellForItem(at: indexPath) else
return
presentPopover(from: self, cell: cell)
func presentPopover(from view: UIViewController, cell: UIView)
let popoverView = PopoverViewController(nibName: "PopoverViewController", bundle: nil)
let popover: UIPopoverPresentationController = popoverView.popoverPresentationController!
popover.sourceRect = cell.bounds
popover.sourceView = cell
view.present(popoverView, animated: true, completion: nil)
而 PopoverViewController 正在使用 modalPresentationStyle = .popover
之前有人在 iOS 13 中遇到过这个问题吗? 我们的应用在 iOS 11 和 12 中运行良好。
我在以下 git 存储库中有此行为的示例:https://github.com/diegodossantos95/UICollectionViewPopoverBug
在存储库中重现的步骤:
点击收集单元格
弹出窗口打开
等待重新加载数据
谢谢,
迭戈。
【问题讨论】:
我现在找到了一种解决方法:当弹出框可见时手动更新每个可见单元格,因此我不需要调用 reloadItems 和 reloadData。 【参考方案1】:您可以使用从单元格的框架创建的临时 UIView,然后将弹出框附加到该单元格,而不是将弹出框附加到您可以保证不会出队的单元格。这是完成此操作的相关代码。
class ViewController: UIViewController
var timer = Timer()
var popOverTempView = UIView()
@IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad()
super.viewDidLoad()
timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(reloadData), userInfo: nil, repeats: true)
self.collectionView.addSubview(popOverTempView)
popOverTempView.isHidden = true
popOverTempView.backgroundColor = .clear
extension ViewController: UICollectionViewDelegate
func presentPopover(from view: UIViewController, cell: UIView)
let popoverView = PopoverViewController(nibName: "PopoverViewController", bundle: nil)
let popover: UIPopoverPresentationController = popoverView.popoverPresentationController!
popoverView.delegate = self
popOverTempView.frame = cell.frame
popOverTempView.isHidden = false
popover.sourceRect = popOverTempView.bounds
popover.sourceView = popOverTempView
view.present(popoverView, animated: true, completion: nil)
extension ViewController: PopoverViewControllerDelegate
func willDismissPopover()
popOverTempView.isHidden = true
protocol PopoverViewControllerDelegate
func willDismissPopover()
class PopoverViewController: UIViewController
var delegate: PopoverViewControllerDelegate?
override func viewWillDisappear(_ animated: Bool)
super.viewWillDisappear(animated)
delegate?.willDismissPopover()
2020 年 5 月 20 日更新:
我想我找到了一个更干净更直接的解决方法。与其直接使用单元格的边界,不如将其 contentView 的框架转换为 collectionView 的坐标空间,然后将其用作 sourceRect 并从当前视图控制器的视图中呈现。
func presentPopover(from view: UIViewController, cell: UICollectionViewCell, indexPath: IndexPath)
let popoverView = PopoverViewController(nibName: "PopoverViewController", bundle: nil)
let popover: UIPopoverPresentationController = popoverView.popoverPresentationController!
var rect = cell.convert(cell.contentView.frame, to: collectionView)
rect = collectionView.convert(rect, to: self.view)
popover.sourceRect = rect
popover.sourceView = self.view
view.present(popoverView, animated: true, completion: nil)
【讨论】:
谢谢,您的解决方法有效,但我仍在寻找更干净的方法来修复它。我不明白为什么我的代码在 iOS 11/12 中运行良好,而不是在 13 中。 我能找到的最佳解决方法是从集合中获取所有可见单元格,然后在弹出框可见时手动更新每个单元格。 我想我可能已经找到了您最初正在寻找的修复程序。检查答案的更新部分。 太棒了,我要测试一下。谢谢。【参考方案2】:当您调用 reloadData 时,这会导致集合视图丢弃所有当前可见的项目(包括占位符)并根据数据源对象的当前状态重新创建项目。
查看reload数据前后cell帧的差异:
- some : <UICollectionViewCell: 0x7fd8abd02190; frame = (73.5 10; 50 50); clipsToBounds = YES; hidden = YES; opaque = NO; layer = <CALayer: 0x600001b50e20>>
- some : <UICollectionViewCell: 0x7fd8abd02190; frame = (519.5 10; 50 50); clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x600001b50e20>>
如果您只需要更改集合中的一个或多个项目,请尝试使用:
func reloadItems(at: [IndexPath])
【讨论】:
在我的应用程序中,我需要重新加载集合视图中的所有可见单元格,因此我必须获取可见单元格的所有索引并调用 reloadItems,但结果是一样的,弹出框移动到另一个细胞。我想了解为什么代码在 iOS 12 中有效,而在 iOS 13 中无效。以上是关于移动时附加到 UICollectionView 中的单元格的弹出框被称为此集合视图的 ReloadData的主要内容,如果未能解决你的问题,请参考以下文章
将附加视图插入从 Xib 加载的 UICollectionView
UICollectionView在初始化的时候移动到某个距离