创建方法以动态确定哪个UICollectionViewCell位于屏幕的中心

时间:2017-01-06 00:08:38

标签: ios objective-c uiscrollview uicollectionview uicollectionviewcell

我目前正在开发一个Objective-C iOS应用程序,该应用程序具有全屏幕集合视图的场景,单元格几乎与整个屏幕的大小垂直向下滚动场景。

我希望能够以编程方式更改位于可见屏幕中心的此Collection视图中的单元格,以及我当前实现此功能的方式是等待滚动停止在Collection View上,以及然后编辑位于屏幕正中心的任何单元格,如下面的方法所示:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{

    NSIndexPath *centerCellIndexPath =
    [self.collectionViewFollwersFeed indexPathForItemAtPoint:
     [self.view convertPoint:[self.view center] toView:self.collectionViewFollwersFeed]];

    UICollectionViewCell *cell;
    NSString *CellIdentifier;

    CellIdentifier = @"FollowersFeed";
    cell = [_collectionViewFollwersFeed cellForItemAtIndexPath:centerCellIndexPath];

    //edit cell here

}

虽然这种实现此功能的方法在某种程度上起作用,但只有当用户停止滚动时才会开始对单元格进行更改。

我希望能够在新单元格覆盖中心位置时开始对中心单元格进行更改,而不必停止滚动。如何编辑此方法,以便当且仅当新单元格覆盖屏幕的中心位置时,应该调用此方法?

3 个答案:

答案 0 :(得分:3)

我完全同意受过良好教育的同伴dahn

话虽如此,您可能希望根据滚动位置实际制作动画,而不是仅仅在碰到中心时“更改”单元格...

要做到这一点,你可以让细胞跟踪自己的位置:

在实例化时将scrollview传递给单元格:

// MyCollectionView's DataSource

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"yourIdentifier" forIndexPath:indexPath];
    cell.observedScrollView = theScrollViewYouWantToTrack;
    [cell startObservingPosition];
    return cell;
}

确保单元格保持observedScrollView弱,以避免保留周期

然后在你的单元格的.m文件中注册一个KVO观察者:

// MyCollectionViewCell.m

- (void)startObservingPosition {
   if (self.observedScrollView) {
      [self.observedScrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial context:NULL];
   }
}

确保在单元格解除分配之前移除KVO观察者......否则崩溃!你也可以考虑使用我自己发布的漂亮enhanced KVO observer

每次KVO Observer触发(当scrollView滚动时) - 您可以找出位置并做出相应的反应。

此示例显示了如何检测细胞何时位于中心,还说明了如何进行更多操作:

// MyCollectionViewCell.m

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *, id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"contentOffset"]) {
      if (self.observedScrollView) {  
         CGPoint offset = self.observedScrollView.contentOffset;
         CGRect contentViewRect = [self.contentView convertRect:self.contentView.bounds toView:self.observedScrollView];
         CGFloat contentViewCenterY = contentViewRect.origin.y + contentView.size.height * 0.5 - offset.y;
         if (contentViewCenterY == self.observedScrollView.bounds.height * 0.5) {
            // the contentView is in the center of the viewable feed. do your animations...
         }  
      }
    }
} 

答案 1 :(得分:1)

编辑单元格== yuck。改变模型==很好。

因此,将NSInteger添加到数据源indexOverCenter。将其初始化为无效的内容,例如-1。然后,在委托中,检测条件:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{

    NSIndexPath *centerCellIndexPath =
    [self.collectionViewFollwersFeed indexPathForItemAtPoint:
     [self.view convertPoint:[self.view center] toView:self.collectionViewFollwersFeed]];

    self.indexOverCenter = centerCellIndexPath.row;
    // don't edit the cell here:  yuck
    // reload it:  nice
    [self.collectionViewFollwersFeed reloadItemsAtIndexPaths:@[ centerCellIndexPath ]];
}

你的&#34;编辑&#34;在cellForItemAtIndex中工作,将传递的indePath行与indexOverCenter进行比较。如果它们相同,那么在那里进行特殊格式化。

答案 2 :(得分:0)

在我的CollectionView中,我得到了这样的结果:

private func findCenterIndex() -> Int {
        let center = self.view.convert(numberCollectionView.center, to: self.numberCollectionView)
        let row = numberCollectionView!.indexPathForItem(at: center)?.row


        guard let index = row else {

            return 0
        }


        self.rating = index

        return index

    }

因此,您可以轻松将其转换为您的objective-c代码