web-dev-qa-db-fra.com

UICollectionView: chemin d'index actuel pour le contrôle de page

J'utilise UICollectionView avec une disposition de flux pour afficher une liste de cellules. J'ai également un contrôle de page pour indiquer la page en cours, mais il semble n'y avoir aucun moyen d'obtenir le chemin d'index en cours. Je sais que je peux obtenir des cellules visibles:

Index de cellules visibles visibles UICollectionView

cependant, il peut y avoir plus d'une cellule visible, même si chacune de mes cellules occupe toute la largeur de l'écran, si je le fais défiler pour avoir deux moitiés de deux cellules, elles sont toutes deux visibles. Il existe donc un moyen d'en obtenir une seule. indice actuel de la cellule visible?

Merci

21
hzxu

Vous pouvez obtenir l'index actuel en surveillant contentOffset dans le délégué scrollViewDidScroll.

ce sera quelque chose comme ça

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    NSInteger currentIndex = self.collectionView.contentOffset.x / self.collectionView.frame.size.width;

}
46
andykkt

Obtenir la page via NSIndexPath du centre de la vue.

Fonctionne même votre page pas égale à la largeur de 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
    }
}
14
Dmitry Coolerov

Vous devez absolument attraper l'élément visible lorsque le défilement est arrêté Utilisez le code suivant pour le faire.

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    if let indexPath = myCollectionView.indexPathsForVisibleItems.first {
        myPageControl.currentPage = indexPath.row
    }
}
12
Jorge Paiz
  1. Placez PageControl dans votre vue ou par code.
  2. Set UIScrollViewDelegate
  3. Dans Collectionview -> cellForItemAtIndexPath (Method), ajoutez le code ci-dessous Pour calculer le nombre de pages,

    int pages = floor(ImageCollectionView.contentSize.width/ImageCollectionView.frame.size.width);
    [pageControl setNumberOfPages:pages];
    
  4. Ajoutez la méthode ScrollView Delegate ,

    #pragma mark - UIScrollVewDelegate 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);
    }
    
4
Ramdhas

La situation était identique dans UICollectionViewScrollDirectionHorizontal, ma structure de flux, et j’utilisais le contrôle de page pour afficher la page en cours.

Je l'ai réalisé en utilisant custom flow layout

/------------------------Header file (.h) pour en-tête personnalisé ---------- -------------- /

/**
* 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

/ ------------------- Fichier d'implémentation (.m) pour en-tête personnalisé ------------------- /

@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;
}

Votre classe contenant la vue collection doit être conforme au protocole 'CustomViewFlowLayoutDelegate' décrit précédemment dans le fichier d'en-tête de présentation personnalisé. Comme:

@interface MyCollectionViewController () <UICollectionViewDataSource, UICollectionViewDelegate, CustomViewFlowLayoutDelegate>
@property (strong, nonatomic) IBOutlet UICollectionView *collectionView;
@property (strong, nonatomic) IBOutlet UIPageControl *pageControl;
....
....
@end

Il existe deux façons de lier votre mise en page personnalisée à la vue de collection, soit dans xib OR dans le code, comme dans in viewDidLoad:

customViewFlowLayout *flowLayout = [[customViewFlowLayout alloc]init];
flowLayout.delegate = self;
self.collectionView.collectionViewLayout = flowLayout;
self.collectionView.pagingEnabled = YES; //Matching your situation probably?

Dernière chose, dans le fichier d'implémentation MyCollectionViewController, implémentez la méthode déléguée de 'CustomViewFlowLayoutDelegate'.

- (void)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout cellCenteredAtIndexPath:(NSIndexPath *)indexPath {
self.pageControl.currentPage = indexPath.row;

}

J'espère que cela serait utile. :)

2
Hitesh Savaliya
(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);
}
0
Davender Verma Soni

pour Swift 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)
    }
}

vous pouvez ignorer la fonction _SetTimer (), c'est pour le défilement automatique

0
Mr Zee