13

我想在我的应用程序中实现“卡片”,例如 Safari 选项卡或 App Store 搜索。

我将在屏幕中心向用户显示一张卡片,并在左右两侧显示上一张和下一张卡片的一部分。(例如,请参阅 App Store 搜索或 Safari 选项卡)

我决定使用UICollectionView,我需要更改页面大小(没有找到如何)或实现自己的布局子类(不知道如何)?

请问有什么帮助吗?

4

6 回答 6

26

下面是我发现获得这种效果的最简单方法。它涉及您的收藏视图和一个额外的秘密滚动视图。

设置您的收藏视图

  • 设置您的集合视图及其所有数据源方法。
  • 框架集合视图;它应该跨越您希望可见的整个宽度。
  • 设置集合视图的contentInset

    _collectionView.contentInset = UIEdgeInsetsMake(0, (self.view.frame.size.width-pageSize)/2, 0, (self.view.frame.size.width-pageSize)/2);
    

这有助于正确偏移单元格。

设置你的秘密滚动视图

  • 创建一个滚动视图,将其放置在您喜欢的任何位置。hidden如果您愿意,可以将其设置为。
  • 将滚动视图边界的大小设置为页面所需的大小。
  • 将自己设置为滚动视图的代表。
  • 将其设置contentSize为集合视图的预期内容大小。

移动手势识别器

  • 将秘密滚动视图的手势识别器添加到集合视图中,并禁用集合视图的手势识别器:

    [_collectionView addGestureRecognizer:_secretScrollView.panGestureRecognizer];
    _collectionView.panGestureRecognizer.enabled = NO;
    

代表

- (void) scrollViewDidScroll:(UIScrollView *)scrollView {
    CGPoint contentOffset = scrollView.contentOffset;
    contentOffset.x = contentOffset.x - _collectionView.contentInset.left;
    _collectionView.contentOffset = contentOffset;
}

随着滚动视图的移动,获取它的偏移量并将其设置为集合视图的偏移量。

我在这里写了关于这个的博客,所以请查看此链接以获取更新: http: //khanlou.com/2013/04/paging-a-overflowing-collection-view/

于 2013-04-17T21:28:30.703 回答
6

您可以继承 UICollectionViewFlowLayout 并像这样覆盖:

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)contentOffset 
                                 withScrollingVelocity:(CGPoint)velocity
{
    NSArray* layoutAttributesArray = 
   [self layoutAttributesForElementsInRect:self.collectionView.bounds];

    if(layoutAttributesArray.count == 0)
        return contentOffset;


    UICollectionViewLayoutAttributes* candidate = 
    layoutAttributesArray.firstObject;

    for (UICollectionViewLayoutAttributes* layoutAttributes in layoutAttributesArray)
    {
        if (layoutAttributes.representedElementCategory != UICollectionElementCategoryCell)
            continue;


        if((velocity.x > 0.0 && layoutAttributes.center.x > candidate.center.x) ||
           (velocity.x <= 0.0 && layoutAttributes.center.x < candidate.center.x))
            candidate = layoutAttributes;


    }

    return CGPointMake(candidate.center.x - self.collectionView.bounds.size.width * 0.5f, contentOffset.y);
}

这将根据速度获得下一个或上一个单元格......但是它不会捕捉到当前单元格。

于 2014-03-17T12:39:00.363 回答
2

@Mike M在 Swift 中的回答……</p>

class CenteringFlowLayout: UICollectionViewFlowLayout {

    override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {

        guard let collectionView = collectionView,
            let layoutAttributesArray = layoutAttributesForElementsInRect(collectionView.bounds),
            var candidate = layoutAttributesArray.first else { return proposedContentOffset }

        layoutAttributesArray.filter({$0.representedElementCategory == .Cell }).forEach { layoutAttributes in

            if (velocity.x > 0 && layoutAttributes.center.x > candidate.center.x) ||
                (velocity.x <= 0 && layoutAttributes.center.x < candidate.center.x) {
                candidate = layoutAttributes
            }
        }

        return CGPoint(x: candidate.center.x - collectionView.bounds.width / 2, y: proposedContentOffset.y)
    }

}
于 2016-08-17T13:07:34.807 回答
1

对 Soroush 的回答进行了一点编辑,这对我有用。我所做的唯一编辑而不是禁用手势:

[_collectionView addGestureRecognizer:_secretScrollView.panGestureRecognizer];
_collectionView.panGestureRecognizer.enabled = NO;

我禁用了collectionview上的滚动:

_collectionView.scrollEnabled = NO;

由于禁用手势也禁用了秘密滚动视图手势。

于 2013-10-21T09:08:21.037 回答
0

我将添加另一个解决方案。就地捕捉并不完美(不如设置启用分页时那么好,但效果很好)。

我已经尝试实施 Soroush 的解决方案,但它对我不起作用。

因为它UICollectionView是它的子类,UIScrollView所以它会响应一个重要的UIScrollViewDelegate方法,即:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
                     withVelocity:(CGPoint)velocity
              targetContentOffset:(inout CGPoint *)targetContentOffset

targetContentOffset一个inout 指针)让您重新定义集合视图的停止点(x在这种情况下,如果您水平滑动)。

关于以下几个变量的快速说明:

  • self.cellWidth– 这是您的集合视图单元格的宽度(如果您愿意,您甚至可以在那里对其进行硬编码)

  • self.minimumLineSpacing– 这是您在单元格之间设置的最小行距

  • self.scrollingObjects是集合视图中包含的对象数组(我需要这个主要是为了计数,知道什么时候停止滚动)

因此,想法是在集合视图的委托中实现此方法,如下所示:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
                     withVelocity:(CGPoint)velocity
              targetContentOffset:(inout CGPoint *)targetContentOffset
{       
    if (self.currentIndex == 0 && velocity.x < 0) {
        // we have reached the first user and we're trying to go back
        return;
    }

    if (self.currentIndex == (self.scrollingObjects.count - 1) && velocity.x > 0) {
        // we have reached the last user and we're trying to go forward
        return;
    }

    if (velocity.x < 0) {
        // swiping from left to right (going left; going back)
        self.currentIndex--;
    } else {
        // swiping from right to left (going right; going forward)
        self.currentIndex++;
    }

    float xPositionToStop = 0;

    if (self.currentIndex == 0) {
        // first row
        xPositionToStop = 0;
    } else {
        // one of the next ones
        xPositionToStop = self.currentIndex * self.cellWidth + (self.currentIndex + 1) * self.minimumLineSpacing - ((scrollView.bounds.size.width - 2*self.minimumLineSpacing - self.cellWidth)/2);
    }

    targetContentOffset->x = xPositionToStop;

    NSLog(@"Point of stopping: %@", NSStringFromCGPoint(*targetContentOffset));
}

期待您提供的任何反馈,这些反馈可以使卡扣效果更好。我也会继续寻找更好的解决方案...

于 2014-03-28T15:12:57.450 回答
-6

前面比较复杂,UICollectionView 是 UIScrollView 的子类,那么就这样做吧:</p>

[self.collectionView setPagingEnabled:YES];

你们都准备好了。

请参阅此详细教程

于 2013-06-16T11:54:00.210 回答