【问题标题】:UICollectionView auto scroll to cell at IndexPathUICollectionView 自动滚动到 IndexPath 处的单元格
【发布时间】:2013-04-05 19:40:35
【问题描述】:

在加载集合视图之前,用户设置集合视图数组中的图像数量。所有单元格都不适合屏幕。我有 30 个单元格,但屏幕上只有 6 个。

问题:如何在加载 UICollectionView 时自动滚动到具有所需图像的单元格?

【问题讨论】:

    标签: ios uicollectionview


    【解决方案1】:

    新的、已编辑的答案:

    将此添加到viewDidLayoutSubviews

    SWIFT

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        let indexPath = IndexPath(item: 12, section: 0)
        self.collectionView.scrollToItem(at: indexPath, at: [.centeredVertically, .centeredHorizontally], animated: true)
    }
    

    一般情况下.centerVertically是这样的

    ObjC

    -(void)viewDidLayoutSubviews {
       [super viewDidLayoutSubviews];
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:12 inSection:0];
       [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically | UICollectionViewScrollPositionCenteredHorizontally animated:NO];
    }
    

    适用于旧 iOS 的旧答案

    将此添加到viewWillAppear

    [self.view layoutIfNeeded];
    [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO];
    

    【讨论】:

    • 这正是我想要使用的。我有数组中对象的编号,并且知道该对象的名称。但不知道如何放置正确的 indexPath...有什么想法吗?
    • 您可以轻松创建indexPath:[NSIndexPath indexPathForItem:numberOfTheObject inSection:sectionNumber]
    • 有一些错误。但是后来我把所有提到的代码都放在了 (void)viewDidLayoutSubviews{} 中,现在它工作正常了。谢谢博格丹。
    • 如何“放大”单元格并放大显示?
    • 这在 iOS 7.1 上无法可靠运行,并可能导致集合视图显示为黑屏。我也不想像下面 viewDidLayoutSubviews 中的解决方案那样保持状态。我所做的只是在调用 scrollToItemAtIndexPath 之前执行了一个 [self.view layoutIfNeeded]
    【解决方案2】:

    我完全同意上面的答案。唯一的问题是,对我来说,解决方案是在 viewDidAppear 中设置代码

    viewDidAppear 
    {
        [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES];
    }
    

    当我使用 viewWillAppear 时,滚动不起作用。

    【讨论】:

    • viewDidAppear 的缺点是你看到集合视图移动/闪烁,视图已经出现(顾名思义)......我真的很想知道为什么苹果没有设计这个不那么不寻常的案例更好的方式,viewDidLayoutSubviews方式有点别扭
    【解决方案3】:

    我发现在viewWillAppear 中滚动可能无法可靠地工作,因为集合视图尚未完成其布局;您可能会滚动到错误的项目。

    我还发现滚动viewDidAppear 会导致未滚动视图的瞬间闪烁可见。

    而且,如果您每次滚动通过viewDidLayoutSubviews,用户将无法手动滚动,因为某些集合布局会在您每次滚动时导致子视图布局。

    以下是我发现的可靠方法:

    目标 C:

    - (void)viewDidLayoutSubviews {
        [super viewDidLayoutSubviews];
    
        // If we haven't done the initial scroll, do it once.
        if (!self.initialScrollDone) {
            self.initialScrollDone = YES;
        
            [self.collectionView scrollToItemAtIndexPath:self.myInitialIndexPath
                                        atScrollPosition:UICollectionViewScrollPositionRight animated:NO];
        }
    }
    

    斯威夫特:

     override func viewWillLayoutSubviews() {
    
        super.viewWillLayoutSubviews()
    
          if !self.initialScrollDone {
    
             self.initialScrollDone = true
             self.testNameCollectionView.scrollToItem(at:selectedIndexPath, at: .centeredHorizontally, animated: true)
        }
    
    }
    

    【讨论】:

    • 不错的提示。我将强调像 LenK 所做的那样使用 initialScrollDone 标志,因为此方法将被多次调用,并且如果您多次调用 scrollToItemAtIndexPath: 似乎会使 collectionView 无法滚动(iOS 模拟器 iPhone 5/iOS 8)跨度>
    • 在 iOS8 中运行良好。应该是公认的答案。
    • 这在 iOS 8.3 中对我不起作用。之前必须调用[self.collectionView layoutIfNeeded];,当您在viewDidLoad 中执行此操作时也可以使用。
    • 这绝对应该是公认的答案。上面的答案给了我一个闪光,因为第一个单元格显示出来,然后用我的新单元格更新,这种方法无缝过渡。
    • 这也适用于 iOS 9,也不会弄乱我的自动布局。
    【解决方案4】:

    这似乎对我有用,它类似于另一个答案,但有一些明显的区别:

    - (void)viewDidLayoutSubviews
    {     
       [self.collectionView layoutIfNeeded];
       NSArray *visibleItems = [self.collectionView indexPathsForVisibleItems];
       NSIndexPath *currentItem = [visibleItems objectAtIndex:0];
       NSIndexPath *nextItem = [NSIndexPath indexPathForItem:someInt inSection:currentItem.section];
    
       [self.collectionView scrollToItemAtIndexPath:nextItem atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
    }
    

    【讨论】:

      【解决方案5】:

      斯威夫特:

      your_CollectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: UICollectionViewScrollPosition.CenteredHorizontally, animated: true)
      

      斯威夫特 3

      let indexPath = IndexPath(row: itemIndex, section: sectionIndex)
      
      collectionView.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition.right, animated: true)
      

      滚动位置:

      UICollectionViewScrollPosition.CenteredHorizontally / UICollectionViewScrollPosition.CenteredVertically
      

      【讨论】:

        【解决方案6】:

        您可以使用 GCD 将滚动分派到 viewDidLoad 中的主运行循环的下一次迭代中以实现此行为。滚动将在集合视图显示在屏幕上之前执行,因此不会闪烁。

        - (void)viewDidLoad {
            dispatch_async (dispatch_get_main_queue (), ^{
                NSIndexPath *indexPath = YOUR_DESIRED_INDEXPATH;
                [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
            });
        }
        

        【讨论】:

        • position为3时如何获取indexpath?
        【解决方案7】:

        这里的所有答案 - 黑客。我找到了在 relaodData 之后在某处滚动集合视图的更好方法:
        子类集合视图布局您使用什么布局,覆盖方法 prepareLayout,在超级调用之后设置您需要的任何偏移量。
        例如:https://stackoverflow.com/a/34192787/1400119

        【讨论】:

          【解决方案8】:

          我建议在collectionView: willDisplay: 中执行此操作,然后您可以确定集合视图委托提供了一些东西。 这是我的例子:

          func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
              /// this is done to set the index on start to 1 to have at index 0 the last image to have a infinity loop
              if !didScrollToSecondIndex {
                  self.scrollToItem(at: IndexPath(row: 1, section: 0), at: .left, animated: false)
                  didScrollToSecondIndex = true
              }
          }
          

          【讨论】:

          • 我发现使用 didEndDisplaying 而不是 willDisplay 是让它正常工作的方法。只要单元格在屏幕上,willDisplay 就可以了;但是,如果单元格尚未出现在屏幕上,则此方法不会将我滚动到它。 didEndDisplaying 虽然非常适合该用例。感谢您的回答让我走上了正确的道路!
          【解决方案9】:

          作为上述的替代方案。 数据加载后调用:

          斯威夫特

          collectionView.reloadData()
          collectionView.layoutIfNeeded()
          collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .right)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-10-11
            • 2021-07-04
            相关资源
            最近更新 更多