223*_*x95 3 uikit ios uicollectionview swift uicollectionviewcompositionallayout
我遇到一个问题,我的 UICollectionView 使用 UICollectionViewCompositionalLayout + Diffable 数据源不允许我平滑地设置垂直单元格扩展的动画。我有一个类似于 UITableView 的全角单元格列,我试图展开单元格以在选择单元格时显示截断的文本。
这在没有动画的情况下工作得很好,但是当我尝试对其进行动画处理时,如果扩展单元格下方的单元格将最终位置超出屏幕边界,则我无法让它看起来流畅,因为单元格将立即消失而不是被动画“推”向下。该问题可以在链接的 gif 中看到https://i.stack.imgur.com/Hd5Dx.jpg
如果扩展单元格下方的单元格的最终位置位于屏幕边界内,则不会出现此问题,如下所示:https: //i.stack.imgur.com/g0QK9.jpg。
我发现一个较旧的问题似乎有类似的问题:UICollectionView animating cell size change Causes undesirable behavior
那里的答案很旧,对我没有帮助,因为我没有使用 Flow Layout,也没有使用 Obj-C。
我看到许多应用程序(例如 Instagram,当图像标题具有“查看更多”时)可以使用 UICollectionView 实现所需的结果,而不会出现任何动画问题,因此我认为这一定是可能的。
在不查看任何代码的情况下很难诊断您的问题,因此这里有一个示例,证明可以使用UICollectionViewCompositionalLayout和来实现具有平滑动画的垂直扩展单元格UICollectionViewDiffableDataSource。
有两个类值得注意:
Cell:这是垂直扩展UICollectionViewCell。ViewController:这是UIViewController配置集合视图、数据源等的。Cell当通过 选择a时collectionView(_:didSelectItemAt:),将切换数组isExpanded中相应项目的属性items,并通过以下方式更新数据源的快照updateSnapshot():
使用 Single View App 模板创建一个新的 Xcode 项目,并将以下代码放入文件中ViewController.swift:
import UIKit
// MARK: - Cell -
final class Cell: UICollectionViewCell {
static let reuseIdentifier = "Cell"
var isExpanded = false {
didSet { label.numberOfLines = numberOfLines }
}
var numberOfLines: Int { isExpanded ? 0 : 3 }
lazy var label: UILabel = {
let label = UILabel()
label.numberOfLines = numberOfLines
label.frame.size = contentView.bounds.size
label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(label)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func sizeThatFits(_ size: CGSize) -> CGSize {
label.sizeThatFits(size)
}
}
// MARK: - UIViewController -
class ViewController: UIViewController {
struct Item: Hashable {
let text: String
var isExpanded = false
private let uuid = UUID()
}
var items: [Item] = [
.init(
text: """
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore
eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident.
"""
),
.init(
text: """
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore
eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident.
""",
isExpanded: true
)
]
lazy var collectionView: UICollectionView = {
let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createCollectionViewLayout())
collectionView.register(Cell.self, forCellWithReuseIdentifier: Cell.reuseIdentifier)
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
collectionView.contentInset.top = 44
collectionView.backgroundColor = .white
collectionView.delegate = self
return collectionView
}()
lazy var dataSource = UICollectionViewDiffableDataSource<Int, Item>(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Cell.reuseIdentifier, for: indexPath) as? Cell else { fatalError() }
cell.isExpanded = itemIdentifier.isExpanded
cell.label.text = itemIdentifier.text
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(collectionView)
updateSnapshot()
}
private func createCollectionViewLayout() -> UICollectionViewCompositionalLayout {
let layoutSize = NSCollectionLayoutSize.init(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(200)
)
let section = NSCollectionLayoutSection(group:
.vertical(
layoutSize: layoutSize,
subitems: [.init(layoutSize: layoutSize)]
)
)
section.contentInsets = .init(top: 0, leading: 16, bottom: 0, trailing: 16)
section.interGroupSpacing = 20
return .init(section: section)
}
private func updateSnapshot() {
var snapshot = NSDiffableDataSourceSnapshot<Int, Item>()
snapshot.appendSections([0])
snapshot.appendItems(items)
dataSource.apply(snapshot, animatingDifferences: true)
}
}
// MARK: - UICollectionViewDelegate -
extension ViewController: UICollectionViewDelegate {
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let itemIdentifier = dataSource.itemIdentifier(for: indexPath) else { return }
items[indexPath.row] = .init(text: itemIdentifier.text, isExpanded: !itemIdentifier.isExpanded)
updateSnapshot()
}
}
Run Code Online (Sandbox Code Playgroud)