介绍
我将描述我想要达到的效果,然后我将详细说明我目前如何尝试实现这一点以及它的行为有什么问题。我还会提到另一种我看过但根本无法工作的方法。
最相关的代码内嵌在问题的底部,以便快速访问。您可以 Download a zip of the source 或以 的形式获取项目Mercurial Repository 在 BitBucket。该项目现在合并了以下答案中的修复。如果你想要最初提供的损坏版本,它会被标记为“initial-buggy-version”
该项目是概念/峰值的最小证明,用于评估效果是否可行,因此它相当轻巧和简单!
预期效果
该应用程序将显示形成垂直表格的大量离散信息行。该表格将由用户垂直滚动。这是带有 UITableView
的标准行为,您可以使用 UICollectionView
也。但是,该应用程序还必须支持捏合缩放。当你在 table 上捏缩放时,全部 的线应该挤压在一起。当你拉伸(stretch)时,全部 的线应该拉开。
在我的概念证明中,单个单元格没有调整大小,它们只是重新定位得更近或更远。这是有意为之:我认为验证想法的可行性并不重要。
以下是屏幕截图,显示了当前应用程序的缩小和放大方式:
当前实现
我正在使用 UICollectionView
带定制 UICollectionViewLayout
子类。布局定位UICollectionViewCells
在屏幕中间的一个很好的摆动正弦波中。每个UICollectionViewCell
只是一个 UILabel
的容器拿着indexPath
排。UICollectionViewLayout
子类有一个参数来设置它描述的每个单元格之间的垂直间距 UICollectionView
并调整它允许根据需要垂直挤压或拉伸(stretch) table 。
我的 UICollectionViewController
子类有一个 UIPinchGestureRecognizer
.当识别器检测到尺度变化时,UICollectionView
中的垂直单元格间距的布局相应地改变。
无需进一步考虑,缩放将从内容的顶部发生,而不是围绕触摸手势的中心。 UICollectionView
的 contentOffset
在捏合期间调整属性以提供此功能。
手势识别器还需要适应捏合时发生的拖动。这也可以通过更改 UICollectionView
来处理。的 contentOffset
.一些额外的代码允许触摸手势的中心点随着手指添加到手势中/从手势中移除而改变。
请注意 UICollectionView
, 是 UIScrollView
子类,有自己的UIPanGestureRecognizer
与 UIPinchGestureRecogniser
交互由我添加。我不确定这是否会导致问题。
我添加了代码来禁用 UICollectionView
在我的捏合手势期间内置滚动,但这似乎没有太大区别。我尝试使用 gestureRecognizer:shouldRequireFailureOfGestureRecognizer:
做我的 UIPinchGestureRecognizer
使内置失败 UIPanGestureRecognizer
,但这似乎完全阻止了我的捏合识别器工作。我不知道这是我愚蠢,还是 iOS 中的错误。
如前所述,当前 UICollectionViewCell
s 没有调整大小。他们只是重新定位。这是故意的。我认为验证这个概念并不重要。
什么有效
工作位工作得很好。您可以上下拖动表格。在拖动过程中,您可以添加一个手指并开始捏合,然后松开手指并继续拖动,然后添加并捏合,等等。一切都非常流畅。在原版 iPhone 5 上,它可以流畅地支持捏合和平移,在屏幕上查看 > 200 次。
什么不起作用 1
如果您在 View 的顶部或底部出现在屏幕上时尝试捏合和捏合,这一切都会变得有点疯狂。
这两个在捏合手势期间互相打架,这使得内容剧烈地上下闪烁(我绝对不想要!)。
什么不起作用 2
UICollectionView
如果您在滚动时放手,默认滚动会减速,并且当您滚动到内容之外时也会平滑地将内容弹回。目前根本没有处理这些。我尝试过但无法工作的事情
UICollectionView
, 是 UIScrollView
应该有一个内置的 UIPinchGestureRecogniser
如果它设置正确以支持缩放。我想知道我是否可以利用它而不是拥有自己的 UIPinchGestureRecogniser
.我尝试通过设置最小和最大比例并添加 Controller 的捏合处理程序来设置它。但是,我真的不明白我应该从 viewForZoomingInScrollView:
的实现中返回什么。 ,所以我只是用 [[UIView alloc] initWithFrame: [[self collectionView] bounds]]
创建了一个虚拟 View .它使 ScrollView “折叠”为一行,这不是我所追求的!最后(在代码之前)
这是一个很长的问题,所以感谢您的阅读。如果您能帮忙解答,则更加感谢。如果我所说或添加的很多内容无关紧要,我很抱歉!
View Controller 的代码
// 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 在问题中。
我在 viewDidLoad
中添加了以下几行我的方法UICollectionViewController
:
[collectionView setMinimumZoomScale: 0.25];
[collectionView setMaximumZoomScale: 4];
我还更新了示例项目,以便代替文本标签, View 由小圆圈组成。当您放大和缩小时,这些会被调整大小。这是现在的样子(缩小和放大):
在缩放过程中,圆的 View 不会重新绘制,而只是从它们的预缩放大小进行插值。重绘被推迟到缩放完成。这是放大几次后的外观截图:
在后台线程中进行缩放期间的重绘会很棒,这样人工制品就不那么明显了,但这远远超出了这个问题的范围,我也还没有研究过。
您可以在 Bit Bucket 上找到整个项目以及修复程序,以便您可以 grab the files那里。
不好的部分——我不知道它为什么有效
我希望通过回答这个问题,我会对
UIScrollView
有很多新的确定性。缩放。我不。从我读到的关于 UIScrollView 的内容来看,这个“修复”应该没有任何区别,无论如何它应该已经在第一时间起作用了。
一个
UIScrollView
不应该启用滚动,直到你给它一个实现 viewForZoomingInScrollView:
的委托(delegate),我没有做过。
关于ios - 向 UICollectionView 添加双指缩放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20895469/