将缩放缩放添加到UICollectionView

介绍

我将描述我想实现的效果,然后详细说明我目前正在如何实现这一点,以及它现在的行为有什么问题。 我还会提到另外一个我看过的方法,但根本无法工作。

最相关的代码是在问题的底部内联以便快速访问。 您可以下载源代码的压缩文件或将项目作为BitBucket上的Mercurial Repository进行获取。 该项目现在包含下面答案的修复。 如果您想要最初提供的破损版本,则会标记为“初始错误版本”

该项目是一个概念/秒杀的最低限度的certificate,以评估效果是否可行,所以它是相当轻和简单!

期望的效果

该应用程序将显示形成垂直表的大量离散信息行。 该表格将被用户垂直滚动。 这是UITableView标准行为,也可以使用UICollectionView 。 但是,应用程序还必须支持捏缩放。 当你在桌子上缩放变焦时, 所有的线条都应该挤压在一起。 当你拉伸, 所有的线应该分开。

在我的概念certificate中,单个细胞没有resize,只是将它们重新放置在一起或者进一步分开。 这是故意的:我不相信validation这个想法的可行性是至关重要的。

这里的屏幕截图显示了当前App如何缩小和放大:

Zoomed in imageZoomed out image

目前的实施

我正在使用UICollectionView与自定义UICollectionViewLayout子类。 这个布局将UICollectionViewCells定位在屏幕中间的一个很好的正弦波。 每个UICollectionViewCell只是一个容器,用于存放indexPath行的UILabel

UICollectionViewLayout子类有一个参数来设置它描述给UICollectionView每个单元格之间的垂直间距,并且调整这个参数允许表格按需要垂直压扁或拉伸。

我的UICollectionViewController子类有一个UIPinchGestureRecognizer 。 当识别器检测到比例变化时, UICollectionView布局中的垂直单元格间距将UICollectionView更改。

没有进一步考虑,缩放将从内容的顶部发生,而不是在触摸手势的中心。 UICollectionViewcontentOffset属性在调整期间进行调整以提供此function。

手势识别器还需要适应夹捏时发生的拖动。 这也是通过更改UICollectionViewcontentOffset来处理的。 一些额外的代码允许在手指被添加到手势或从手势移除时触摸手势的中心点改变。

请注意,作为UIScrollView子类的UIPanGestureRecognizer具有自己的UIPanGestureRecognizer ,它与我添加的UIPanGestureRecognizer进行交互。 我不确定这是否导致问题。

我添加了代码来禁用UICollectionView的内置滚动在我的捏手势,但这似乎没有太大的区别。 我试图使用gestureRecognizer:shouldRequireFailureOfGestureRecognizer:使我的UIPinchGestureRecognizer失败的内置UIPanGestureRecognizer ,但这似乎停止了我的掐识别器工作。 我不知道这是我是愚蠢的,还是在iOS中的错误。

如前所述,目前的UICollectionViewCell没有resize。 他们只是重新定位。 这是故意的。 我认为这对于validation这个概念并不重要。

什么工作

工作位工作得很好。 您可以上下拖动表格。 在拖动过程中,您可以添加一个手指并开始捏合,然后释放一个手指并继续拖动,然后添加和捏合等。这一切都非常顺利。 在原始的iPhone 5上,它可以顺利地在屏幕上支持> 200视图的捏和平移。

什么不行1

如果在屏幕的顶部或底部进行缩放操作,则会发生一些问题。

  • 在滚动条上,视图被允许拖动,以便将其拉到可见内容之外(我想要的,因为它是iOS上数据列表的标准行为)。
  • 然而,在缩放比例变化时,视图被折回,以便内容被locking在屏幕上(我不希望发生这种情况)。

这两个在捏手势相互争斗,这使得内容猛烈地闪烁上下(我绝对不希望!)。

什么不行2

如果您在滚动时放开, UICollectionView的默认滚动会减速,并且在滚动之外时也顺利地将内容弹回。 这些目前没有处理。

  • 如果您在滚动时释放捏手势,则停止。
  • 如果您用捏手势滚动超出内容,然后释放,它保持在原来的位置,不会反弹。 当你再次开始滚动时,它会跳回内容。

我试过的东西,但无法工作

UICollectionView ,作为UIScrollView应该有一个内置的UIPinchGestureRecogniser如果它设置正确,以支持缩放。 我想知道是否可以利用这个,而不是有我自己的UIPinchGestureRecogniser 。 我试图通过设置最小和最大比例,并添加我的控制器的夹点处理程序来设置它。 但是,我真的不明白我应该从viewForZoomingInScrollView:实现返回什么,所以我只是用[[UIView alloc] initWithFrame: [[self collectionView] bounds]]创build一个虚拟视图。 它使滚动视图“崩溃”到一行,这不是我以后!

最后(在代码之前)

这是一个很长的问题,所以感谢您阅读。 如果你能帮忙解答,谢谢你。 对不起,如果我已经说过或添加了很多不相关的东西!

代码为视图控制器

 // STViewController.m #import "STViewController.h" #import "STDataColumnsCollectionViewLayout.h" #import "STCollectionViewLabelCell.h" @interface STViewController () <UIGestureRecognizerDelegate> @property (nonatomic, assign) CGFloat pinchStartVerticalPeriod; @property (nonatomic, assign) CGFloat pinchNormalisedVerticalPosition; @property (nonatomic, assign) NSInteger pinchTouchCount; -(void) handlePinch: (UIPinchGestureRecognizer *) pinchRecogniser; @end @implementation STViewController -(void) viewDidLoad { [[self collectionView] registerClass: [STCollectionViewLabelCell class] forCellWithReuseIdentifier: [STCollectionViewLabelCell className]]; UICollectionView *const collectionView = [self collectionView]; [collectionView setAllowsSelection: NO]; [_pinchRecogniser addTarget: self action: @selector(handlePinch:)]; [_pinchRecogniser setDelegate: self]; [_pinchRecogniser setCancelsTouchesInView:YES]; [[self view] addGestureRecognizer: _pinchRecogniser]; } #pragma mark - -(NSInteger) collectionView: (UICollectionView *)collectionView numberOfItemsInSection: (NSInteger)section { return 800; } -(UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { STCollectionViewLabelCell *const cell = [[self collectionView] dequeueReusableCellWithReuseIdentifier: [STCollectionViewLabelCell className] forIndexPath: indexPath]; [[cell label] setText: [NSString stringWithFormat: @"%d", [indexPath row]]]; return cell; } #pragma mark - -(BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; } #pragma mark - -(void) handlePinch: (UIPinchGestureRecognizer *) pinchRecogniser { UICollectionView *const collectionView = [self collectionView]; STDataColumnsCollectionViewLayout *const layout = (STDataColumnsCollectionViewLayout *)[self collectionViewLayout]; if(([pinchRecogniser state] == UIGestureRecognizerStateBegan) || ([pinchRecogniser numberOfTouches] != _pinchTouchCount)) { const CGFloat normalisedY = [pinchRecogniser locationInView: collectionView].y / [layout collectionViewContentSize].height; _pinchNormalisedVerticalPosition = normalisedY; _pinchTouchCount = [pinchRecogniser numberOfTouches]; } switch ([pinchRecogniser state]) { case UIGestureRecognizerStateBegan: { NSLog(@"Began"); _pinchStartVerticalPeriod = [layout verticalPeriod]; [collectionView setScrollEnabled: NO]; break; } case UIGestureRecognizerStateChanged: { NSLog(@"Changed"); STDataColumnsCollectionViewLayout *const layout = (STDataColumnsCollectionViewLayout *)[self collectionViewLayout]; const CGFloat newVerticalPeriod = _pinchStartVerticalPeriod * [pinchRecogniser scale]; [layout setVerticalPeriod: newVerticalPeriod]; [[self collectionViewLayout] invalidateLayout]; const CGPoint dragCenter = [pinchRecogniser locationInView: [collectionView superview]]; const CGFloat currentY = _pinchNormalisedVerticalPosition * [layout collectionViewContentSize].height; [collectionView setContentOffset: CGPointMake(0, currentY - dragCenter.y) animated: NO]; } case UIGestureRecognizerStateEnded: case UIGestureRecognizerStateCancelled: { [collectionView setScrollEnabled: YES]; } default: break; } } @end 

好点 – 如何使它工作

上述代码的一些微小的调整已经解决了什么是行不通的1什么不工作问题2

我已经添加了以下行到我的UICollectionViewControllerviewDidLoad方法:

 [collectionView setMinimumZoomScale: 0.25]; [collectionView setMaximumZoomScale: 4]; 

我也更新了示例项目,以便代替文本标签,视图由小圆圈组成。 在放大和缩小时,这些都将resize。 下面是它现在的样子(缩小和放大):

图像缩小图像放大

在缩放过程中,圆圈的视图不会重新绘制,而是从预缩放大小插入。 重绘被推迟,直到缩放完成。 以下是几次放大之后的照片:

在缩放期间

在缩放过程中进行重绘是非常好的,因为这样的人工效果不太明显,但这已经超出了这个问题的范围,而且我也没有做过这方面的工作。

您可以在Bit Bucket上find整个项目,并带有修复程序,以便您可以抓取文件 。

坏的部分 – 我不知道为什么它的作品

我希望有了这个问题的答案,我会有很多关于UIScrollView缩放的确定性。 我不。

从我读过的关于UIScrollView的信息来看,这个“修复”应该没有什么区别,而且它本来应该已经在第一个地方工作了。

UIScrollView是不应该启用滚动,直到你给它一个实现viewForZoomingInScrollView:我还没有做的委托。