提问人:iCodes 提问时间:9/6/2023 更新时间:9/6/2023 访问量:21
确定单元格是否已从集合视图 iOS 中的可见区域滚动
Determine if a cell has scrolled off the visible area in collection view iOS
问:
我有一个集合视图,其中我有一个特定的单元格。如果此单元格在向上滚动时从底部的可见区域滚动,则必须显示视图。我们怎样才能做到这一点?
为了识别这个特定的单元格,我存储了它的 indexPath。现在,如果我们使用下面的检查,即使单元格在向下移动时滚动过去,即单元格已从屏幕顶部滚动,它也是有效的。但是我希望实现的是,当用户向上滚动时,只有当单元格从屏幕底部滚动时,才能找出答案。!collectionView.indexPathsForVisibleItems.contains(specificCellIndexPath)
func scrollViewDidScroll(_ scrollView: UISCrollView) {
if !collectionView.indexPathsForVisibleItems.contains(specificCellIndexPath) {
// show the desired view only when specificCellIndexPath has scrolled past the bottom of the screen.
}
}
答:
0赞
DonMag
9/6/2023
#1
您的目标似乎是想知道:
specificPath
单元格位于集合视图框架下方specificPath
单元格可见specificPath
单元格位于集合视图框架上方
因此,我们将添加一个类属性来查找 specificPath 单元格的 Bottom:
let specificPath: IndexPath = .init(item: 10, section: 0)
// we will update when the specificPath cell is visible
var specificCellBottom: CGFloat = .greatestFiniteMagnitude
在 中,我们可以找出单元格是否可见......如果不是,请确定它是在集合视图框架的上方还是下方:scrollViewDidScroll()
func scrollViewDidScroll(_ scrollView: UIScrollView) {
var cellPosition: Int = 1
if collectionView.indexPathsForVisibleItems.contains(specificPath) {
// cell is Visible
cellPosition = 0
// it's visible, so we know we can get it, but safely unwrap optional
if let c = collectionView.cellForItem(at: specificPath) {
// this will not change after the cell has been shown,
// but no harm in setting it every time
specificCellBottom = c.frame.maxY
}
} else {
if scrollView.contentOffset.y >= specificCellBottom {
cellPosition = -1
}
}
switch cellPosition {
case 1:
// specificPath cell is Below the Collection View
case 0:
// specificPath cell is Visible
default:
// specificPath cell is Above the Collection View
}
}
这里有一个完整的例子可以玩......
简单居中的标签单元格:
class CenterLabelCell: UICollectionViewCell {
let label = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
label.backgroundColor = .yellow
label.font = .systemFont(ofSize: 16.0, weight: .light)
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(label)
let g = contentView.layoutMarginsGuide
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: g.centerXAnchor),
label.centerYAnchor.constraint(equalTo: g.centerYAnchor),
])
}
}
视图控制器示例:
class VisibleCellCollViewVC: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
var collectionView: UICollectionView!
let statusLabel = UILabel()
let specificPath: IndexPath = .init(item: 10, section: 0)
// we will update when the specificPath cell is visible
var specificCellBottom: CGFloat = .greatestFiniteMagnitude
override func viewDidLoad() {
super.viewDidLoad()
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 12.0
layout.scrollDirection = .vertical
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
// we'll put the label below the collection view
statusLabel.textAlignment = .center
statusLabel.text = "\(specificPath) cell is Below the Collection View"
statusLabel.backgroundColor = .cyan
collectionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(collectionView)
statusLabel.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(statusLabel)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
statusLabel.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
statusLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
statusLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
statusLabel.heightAnchor.constraint(equalToConstant: 60.0),
collectionView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
collectionView.bottomAnchor.constraint(equalTo: statusLabel.topAnchor, constant: -20.0),
collectionView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
collectionView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
])
collectionView.register(CenterLabelCell.self, forCellWithReuseIdentifier: "c")
collectionView.dataSource = self
collectionView.delegate = self
collectionView.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return .init(width: collectionView.frame.width * 0.5 - 8.0, height: 200.0)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 50
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "c", for: indexPath) as! CenterLabelCell
cell.label.text = "\(indexPath)"
cell.contentView.backgroundColor = .systemBlue
if indexPath == specificPath {
cell.contentView.backgroundColor = .systemRed
}
return cell
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
var cellPosition: Int = 1
if collectionView.indexPathsForVisibleItems.contains(specificPath) {
// cell is Visible
cellPosition = 0
// it's visible, so we know we can get it, but safely unwrap optional
if let c = collectionView.cellForItem(at: specificPath) {
// this will not change after the cell has been shown,
// but no harm in setting it every time
specificCellBottom = c.frame.maxY
}
} else {
if scrollView.contentOffset.y >= specificCellBottom {
cellPosition = -1
}
}
switch cellPosition {
case 1:
statusLabel.text = "\(specificPath) cell is Below the Collection View"
case 0:
statusLabel.text = "\(specificPath) cell is Visible"
default:
statusLabel.text = "\(specificPath) cell is Above the Collection View"
}
}
}
看起来像这样:
评论