如何检测最后一个单元格在 UICollectionView 中是否可见?
How to detect if last cell is visible in UICollectionView?
我正在尝试检测 collectionView
中的最后一个单元格是否可见。
var isLastCellVisible: Bool {
let lastIndexPath = NSIndexPath(forItem: self.messages.count - 1, inSection: 0)
let visibleIndexPaths = self.collectionView.indexPathsForVisibleItems()
let lastCellPositionY = self.collectionView.layoutAttributesForItemAtIndexPath(lastIndexPath)!.frame.origin.y
let bottomInset = self.collectionView.contentInset.bottom // changes when the keyboard is shown / hidden
let contentHeight = self.collectionView.contentSize.height
if visibleIndexPaths.contains(lastIndexPath) && (contentHeight - lastCellPositionY) > bottomInset {
return true
} else {
return false
}
}
什么有效:
如果最后一个单元格可见并且显示了键盘,因此该单元格未被它隐藏,则上述代码return为真。如果它 是隐藏的 它 return 是假的。
但是当用户向上滚动并且最后一个单元格位于键盘上方时,我不知道如何 return 为真。
当 collectionView
向上滚动时,lastCellPositionY
和 contentHeight
不会改变。
反而
self.collectionView.bounds.origin.y
确实发生了变化,但我不知道如何将 lastCellPositionY
与它进行比较,因为它们的来源不同,而且 self.collectionView.bounds.origin.y
明显小于 lastCellPositionY
。
我使用此代码(翻译为 Swift 来自此线程中的提交:https://github.com/jessesquires/JSQMessagesViewController/issues/1458)
var isLastCellVisible: Bool {
if self.messages.isEmpty {
return true
}
let lastIndexPath = NSIndexPath(forItem: self.messages.count - 1, inSection: 0)
var cellFrame = self.collectionView.layoutAttributesForItemAtIndexPath(lastIndexPath)!.frame
cellFrame.size.height = cellFrame.size.height
var cellRect = self.collectionView.convertRect(cellFrame, toView: self.collectionView.superview)
cellRect.origin.y = cellRect.origin.y - cellFrame.size.height - 100
// substract 100 to make the "visible" area of a cell bigger
var visibleRect = CGRectMake(
self.collectionView.bounds.origin.x,
self.collectionView.bounds.origin.y,
self.collectionView.bounds.size.width,
self.collectionView.bounds.size.height - self.collectionView.contentInset.bottom
)
visibleRect = self.collectionView.convertRect(visibleRect, toView: self.collectionView.superview)
if CGRectContainsRect(visibleRect, cellRect) {
return true
}
return false
}
我在用什么
override func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == dataSource.count - 1 {
// Last cell is visible
}
}
对于Swift 3:
var isLastCellVisible: Bool {
if self.posts.isEmpty {
return true
}
let lastIndexPath = IndexPath(item: self.posts.count - 1, section: 1)
var cellFrame = self.collectionView?.layoutAttributesForItem(at: lastIndexPath)!.frame
cellFrame?.size.height = (cellFrame?.size.height)!
var cellRect = self.collectionView?.convert(cellFrame!, to: self.collectionView?.superview)
cellRect?.origin.y = (cellRect?.origin.y)! - (cellFrame?.size.height)! - 100
// substract 100 to make the "visible" area of a cell bigger
var visibleRect = CGRect(x: (self.collectionView?.bounds.origin.x)!, y: (self.collectionView?.bounds.origin.y)!, width:
(self.collectionView?.bounds.size.width)!, height:
(self.collectionView?.bounds.size.height)! - (self.collectionView?.contentInset.bottom)!
)
visibleRect = (self.collectionView?.convert(visibleRect, to: self.collectionView?.superview))!
if visibleRect.contains(cellRect!) {
return true
}
return false
}
Swift 版本 4.2
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView.bounds.maxY) == scrollView.contentSize.height{
// Call Your API or hide UIElements
}
}
一个方便的扩展,带有两个计算属性。
extension UICollectionView {
var isLastItemFullyVisible: Bool {
let numberOfItems = numberOfItems(inSection: 0)
let lastIndexPath = IndexPath(item: numberOfItems - 1, section: 0)
guard let attrs = collectionViewLayout.layoutAttributesForItem(at: lastIndexPath)
else {
return false
}
return bounds.contains(attrs.frame)
}
// If you don't care if it's fully visible, as long as some of it is visible
var isLastItemVisible: Bool {
let numberOfItems = collectionView.numberOfItems(inSection: 0)
return indexPathsForVisibleItems.contains(where: { [=10=].item == numberOfItems - 1 })
}
}
有 isLastItemFullyVisible 的替代方法。一个班轮。
var isLastItemFullyVisible: Bool {
contentSize.width == contentOffset.x + frame.width - contentInset.right
}
Swift 5
public extension IndexPath {
func isLastRow(at tableView: UITableView) -> Bool {
return row == (tableView.numberOfRows(inSection: section) - 1)
}
func isLastRow(at collectionView: UICollectionView) -> Bool {
return row == (collectionView.numberOfItems(inSection: section) - 1)
}
}
对于集合视图
public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if indexPath.isLastRow(at: collectionView) {
..//
}
}
对于 TableView
public func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if indexPath.isLastRow(at: collectionView) {
..//
}
}
我正在尝试检测 collectionView
中的最后一个单元格是否可见。
var isLastCellVisible: Bool {
let lastIndexPath = NSIndexPath(forItem: self.messages.count - 1, inSection: 0)
let visibleIndexPaths = self.collectionView.indexPathsForVisibleItems()
let lastCellPositionY = self.collectionView.layoutAttributesForItemAtIndexPath(lastIndexPath)!.frame.origin.y
let bottomInset = self.collectionView.contentInset.bottom // changes when the keyboard is shown / hidden
let contentHeight = self.collectionView.contentSize.height
if visibleIndexPaths.contains(lastIndexPath) && (contentHeight - lastCellPositionY) > bottomInset {
return true
} else {
return false
}
}
什么有效:
如果最后一个单元格可见并且显示了键盘,因此该单元格未被它隐藏,则上述代码return为真。如果它 是隐藏的 它 return 是假的。
但是当用户向上滚动并且最后一个单元格位于键盘上方时,我不知道如何 return 为真。
当collectionView
向上滚动时,lastCellPositionY
和 contentHeight
不会改变。
反而
self.collectionView.bounds.origin.y
确实发生了变化,但我不知道如何将 lastCellPositionY
与它进行比较,因为它们的来源不同,而且 self.collectionView.bounds.origin.y
明显小于 lastCellPositionY
。
我使用此代码(翻译为 Swift 来自此线程中的提交:https://github.com/jessesquires/JSQMessagesViewController/issues/1458)
var isLastCellVisible: Bool {
if self.messages.isEmpty {
return true
}
let lastIndexPath = NSIndexPath(forItem: self.messages.count - 1, inSection: 0)
var cellFrame = self.collectionView.layoutAttributesForItemAtIndexPath(lastIndexPath)!.frame
cellFrame.size.height = cellFrame.size.height
var cellRect = self.collectionView.convertRect(cellFrame, toView: self.collectionView.superview)
cellRect.origin.y = cellRect.origin.y - cellFrame.size.height - 100
// substract 100 to make the "visible" area of a cell bigger
var visibleRect = CGRectMake(
self.collectionView.bounds.origin.x,
self.collectionView.bounds.origin.y,
self.collectionView.bounds.size.width,
self.collectionView.bounds.size.height - self.collectionView.contentInset.bottom
)
visibleRect = self.collectionView.convertRect(visibleRect, toView: self.collectionView.superview)
if CGRectContainsRect(visibleRect, cellRect) {
return true
}
return false
}
我在用什么
override func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == dataSource.count - 1 {
// Last cell is visible
}
}
对于Swift 3:
var isLastCellVisible: Bool {
if self.posts.isEmpty {
return true
}
let lastIndexPath = IndexPath(item: self.posts.count - 1, section: 1)
var cellFrame = self.collectionView?.layoutAttributesForItem(at: lastIndexPath)!.frame
cellFrame?.size.height = (cellFrame?.size.height)!
var cellRect = self.collectionView?.convert(cellFrame!, to: self.collectionView?.superview)
cellRect?.origin.y = (cellRect?.origin.y)! - (cellFrame?.size.height)! - 100
// substract 100 to make the "visible" area of a cell bigger
var visibleRect = CGRect(x: (self.collectionView?.bounds.origin.x)!, y: (self.collectionView?.bounds.origin.y)!, width:
(self.collectionView?.bounds.size.width)!, height:
(self.collectionView?.bounds.size.height)! - (self.collectionView?.contentInset.bottom)!
)
visibleRect = (self.collectionView?.convert(visibleRect, to: self.collectionView?.superview))!
if visibleRect.contains(cellRect!) {
return true
}
return false
}
Swift 版本 4.2
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView.bounds.maxY) == scrollView.contentSize.height{
// Call Your API or hide UIElements
}
}
一个方便的扩展,带有两个计算属性。
extension UICollectionView {
var isLastItemFullyVisible: Bool {
let numberOfItems = numberOfItems(inSection: 0)
let lastIndexPath = IndexPath(item: numberOfItems - 1, section: 0)
guard let attrs = collectionViewLayout.layoutAttributesForItem(at: lastIndexPath)
else {
return false
}
return bounds.contains(attrs.frame)
}
// If you don't care if it's fully visible, as long as some of it is visible
var isLastItemVisible: Bool {
let numberOfItems = collectionView.numberOfItems(inSection: 0)
return indexPathsForVisibleItems.contains(where: { [=10=].item == numberOfItems - 1 })
}
}
有 isLastItemFullyVisible 的替代方法。一个班轮。
var isLastItemFullyVisible: Bool {
contentSize.width == contentOffset.x + frame.width - contentInset.right
}
Swift 5
public extension IndexPath {
func isLastRow(at tableView: UITableView) -> Bool {
return row == (tableView.numberOfRows(inSection: section) - 1)
}
func isLastRow(at collectionView: UICollectionView) -> Bool {
return row == (collectionView.numberOfItems(inSection: section) - 1)
}
}
对于集合视图
public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if indexPath.isLastRow(at: collectionView) {
..//
}
}
对于 TableView
public func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if indexPath.isLastRow(at: collectionView) {
..//
}
}