[英]UICollectionView - Find out current index path and change values/data
[英]UICollectionView: current index path for page control
我正在使用帶有流布局的 UICollectionView 來顯示單元格列表,我還有一個頁面控件來指示當前頁面,但似乎無法獲取當前索引路徑,我知道我可以獲得可見單元格:
但是,可以有多個可見單元格,即使我的每個單元格都占據了屏幕的整個寬度,如果我滾動它以獲得兩個單元格的兩半,那么它們都是可見的,所以有沒有辦法只得到一個當前可見單元格的索引?
謝謝
您可以通過在 scrollViewDidScroll 委托中監控 contentOffset 來獲取當前索引
它會是這樣的
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSInteger currentIndex = self.collectionView.contentOffset.x / self.collectionView.frame.size.width;
}
從視圖中心通過 NSIndexPath 獲取頁面。
即使您的頁面不等於 UICollectionView 的寬度也能工作。
func scrollViewDidScroll(scrollView: UIScrollView) {
let center = CGPoint(x: scrollView.contentOffset.x + (scrollView.frame.width / 2), y: (scrollView.frame.height / 2))
if let ip = collectionView.indexPathForItemAtPoint(center) {
self.pageControl.currentPage = ip.row
}
}
當滾動移動停止時,您肯定需要捕獲可見項目。 使用下一個代碼來做到這一點。
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if let indexPath = myCollectionView.indexPathsForVisibleItems.first {
myPageControl.currentPage = indexPath.row
}
}
斯威夫特 5.1
零崩潰的簡單方法和更高的安全性
func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if collectionView == newsCollectionView {
if newsPager.currentPage == indexPath.row {
guard let visible = newsCollectionView.visibleCells.first else { return }
guard let index = newsCollectionView.indexPath(for: visible)?.row else { return }
newsPager.currentPage = index
}
}
}
在Collectionview -> cellForItemAtIndexPath (Method) 中添加以下代碼來計算頁數,
int pages = floor(ImageCollectionView.contentSize.width/ImageCollectionView.frame.size.width); [pageControl setNumberOfPages:pages];
添加ScrollView 委托方法,
#pragma mark - UIScrollViewDelegate for UIPageControl - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { CGFloat pageWidth = ImageCollectionView.frame.size.width; float currentPage = ImageCollectionView.contentOffset.x / pageWidth; if (0.0f != fmodf(currentPage, 1.0f)) { pageControl.currentPage = currentPage + 1; } else { pageControl.currentPage = currentPage; } NSLog(@"finishPage: %ld", (long)pageControl.currentPage); }
我有類似的情況,我的流布局是為 UICollectionViewScrollDirectionHorizontal 設置的,我使用頁面控件來顯示當前頁面。
我使用自定義流布局實現了它。
/------------------------ 自定義標頭的頭文件 (.h) ---------------- --------/
/**
* The customViewFlowLayoutDelegate protocol defines methods that let you coordinate with
*location of cell which is centered.
*/
@protocol CustomViewFlowLayoutDelegate <UICollectionViewDelegateFlowLayout>
/** Informs delegate about location of centered cell in grid.
* Delegate should use this location 'indexPath' information to
* adjust it's conten associated with this cell.
* @param indexpath of cell in collection view which is centered.
*/
- (void)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout cellCenteredAtIndexPath:(NSIndexPath *)indexPath;
@end
@interface customViewFlowLayout : UICollectionViewFlowLayout
@property (nonatomic, weak) id<CustomViewFlowLayoutDelegate> delegate;
@end
/------------------- 自定義標頭的實現文件 (.m) -------------------/
@implementation customViewFlowLayout
- (void)prepareLayout {
[super prepareLayout];
}
static const CGFloat ACTIVE_DISTANCE = 10.0f; //Distance of given cell from center of visible rect
static const CGFloat ITEM_SIZE = 40.0f; // Width/Height of cell.
- (id)init {
if (self = [super init]) {
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
self.minimumInteritemSpacing = 60.0f;
self.sectionInset = UIEdgeInsetsZero;
self.itemSize = CGSizeMake(ITEM_SIZE, ITEM_SIZE);
self.minimumLineSpacing = 0;
}
return self;
}
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
return YES;
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
CGRect visibleRect;
visibleRect.origin = self.collectionView.contentOffset;
visibleRect.size = self.collectionView.bounds.size;
for (UICollectionViewLayoutAttributes *attribute in attributes) {
if (CGRectIntersectsRect(attribute.frame, rect)) {
CGFloat distance = CGRectGetMidX(visibleRect) - attribute.center.x;
// Make sure given cell is center
if (ABS(distance) < ACTIVE_DISTANCE) {
[self.delegate collectionView:self.collectionView layout:self cellCenteredAtIndexPath:attribute.indexPath];
}
}
}
return attributes;
}
包含集合視圖的類必須符合我之前在自定義布局頭文件中描述的協議“CustomViewFlowLayoutDelegate”。 像:
@interface MyCollectionViewController () <UICollectionViewDataSource, UICollectionViewDelegate, CustomViewFlowLayoutDelegate>
@property (strong, nonatomic) IBOutlet UICollectionView *collectionView;
@property (strong, nonatomic) IBOutlet UIPageControl *pageControl;
....
....
@end
有兩種方法可以將自定義布局掛鈎到集合視圖,要么在 xib 中,要么在代碼中,例如在 viewDidLoad 中說的:
customViewFlowLayout *flowLayout = [[customViewFlowLayout alloc]init];
flowLayout.delegate = self;
self.collectionView.collectionViewLayout = flowLayout;
self.collectionView.pagingEnabled = YES; //Matching your situation probably?
最后一件事,在 MyCollectionViewController 實現文件中,實現“CustomViewFlowLayoutDelegate”的委托方法。
- (void)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout cellCenteredAtIndexPath:(NSIndexPath *)indexPath {
self.pageControl.currentPage = indexPath.row;
}
我希望這會有所幫助。 :)
快速 4.2
@IBOutlet weak var mPageControl: UIPageControl!
@IBOutlet weak var mCollectionSlider: UICollectionView!
private var _currentIndex = 0
private var T1:Timer!
private var _indexPath:IndexPath = [0,0]
private func _GenerateNextPage(){
self._currentIndex = mCollectionSlider.indexPathForItem(at: CGPoint.init(x: CGRect.init(origin: mCollectionSlider.contentOffset, size: mCollectionSlider.bounds.size).midX, y: CGRect.init(origin: mCollectionSlider.contentOffset, size: mCollectionSlider.bounds.size).midY))?.item ?? 0
self.mPageControl.currentPage = self._currentIndex
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
_SetTimer(AutoScrollInterval)
_GenerateNextPage()
}
@objc private func _AutoScroll(){
self._indexPath = IndexPath.init(item: self._currentIndex+1, section: 0)
if !(self._indexPath.item < self.numberOfItems){
_indexPath = [0,0]
}
self.mCollectionSlider.scrollToItem(at: self._indexPath, at: .centeredHorizontally, animated: true)
}
private func _SetTimer(_ interval:TimeInterval){
if T1 == nil{
T1 = Timer.scheduledTimer(timeInterval: interval , target:self , selector: #selector(_AutoScroll), userInfo: nil, repeats: true)
}
}
您可以跳過函數 _SetTimer() ,即自動滾動
注意- 我發現andykkt 的答案很有用,但由於它在 obj-c 中將其轉換為 swift 並且還在另一個UIScrollView
委托中實現了邏輯以獲得更平滑的效果。
func updatePageNumber() {
// If not case to `Int` will give an error.
let currentPage = Int(ceil(scrollView.contentOffset.x / scrollView.frame.size.width))
pageControl.currentPage = currentPage
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
// This will be call when you scrolls it manually.
updatePageNumber()
}
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
// This will be call when you scrolls it programmatically.
updatePageNumber()
}
使用 UICollectionViewDelegate 方法
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
pageControl.currentPage = indexPath.row
}
func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if pageControl.currentPage == indexPath.row {
pageControl.currentPage = collectionView.indexPath(for: collectionView.visibleCells.first!)!.row
}
}
(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat pageWidth = _cvImagesList.frame.size.width;
float currentPage = _cvImagesList.contentOffset.x / pageWidth;
_pageControl.currentPage = currentPage + 1;
NSLog(@"finishPage: %ld", (long)_pageControl.currentPage);
}
extension youriewControllerName:UIScrollViewDelegate{
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageWidth = self.collectionView.frame.size.width
pageControl.currentPage = Int(self.collectionView.contentOffset.x / pageWidth)
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.