Подтвердить что ты не робот

UICollectionView: текущий путь указателя для управления страницей

Я использую UICollectionView с макетом потока, чтобы показать список ячеек, у меня также есть элемент управления страницей для указания текущей страницы, но, похоже, нет способа получить текущий путь указателя, я знаю, что могу получить видимый клетки:

UICollectionView текущий видимый индекс ячейки

однако может быть более чем одна видимая клетка, даже если каждая из моих ячеек занимает всю ширину экрана, если я прокручиваю ее, чтобы иметь две половины из двух ячеек, то они оба видны, так что есть способ получить только один текущий видимый индекс ячейки?

Спасибо

4b9b3361

Ответ 1

Вы можете получить текущий индекс, проверив contentOffset в делегате scrollViewDidScroll

это будет что-то вроде этого

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

}

Ответ 2

Получить страницу через 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
    }
}

Ответ 3

Определенно вам нужно поймать видимый элемент, когда движение прокрутки остановлено. Используйте следующий код, чтобы сделать это.

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    if let indexPath = myCollectionView.indexPathsForVisibleItems.first {
        myPageControl.currentPage = indexPath.row
    }
}

Ответ 4

  1. Поместите PageControl на ваш взгляд или установить по коду.
  2. Установить UIScrollViewDelegate
  3. В Collectionview → cellForItemAtIndexPath (Method) добавьте приведенный ниже код для расчета количества страниц,

    int pages = floor(ImageCollectionView.contentSize.width/ImageCollectionView.frame.size.width);
    [pageControl setNumberOfPages:pages];
    
  4. Добавьте метод делегата 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);
    }
    

Ответ 5

У меня была схожая ситуация, когда моя компоновка потока была настроена для 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 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 OR, либо в коде, например say в 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;

}

Надеюсь, это будет полезно.:)

Ответ 6

для быстрой 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(), то есть для автоматической прокрутки

Ответ 7

(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);
}

Ответ 8

Примечание. Я нашел полезный ответ 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()
}

Ответ 9

С помощью методов 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
    }
}