当前位置: 首页 > 知识库问答 >
问题:

将捏合缩放添加到 UI 集合视图

阙沛
2023-03-14

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

最相关的代码内嵌在问题的底部,以便快速访问。您可以下载源代码的zip文件,或者在BitBucket上获得作为Mercurial资源库的项目。该项目现在合并了以下答案中的修复。如果您想要最初提供的不完整版本,它会被标记为“初始错误版本”

该项目是一个极小的概念验证/尖峰来评估效果是否可行,所以它相当轻和简单!

该应用程序将显示大量形成垂直表格的离散信息行。该表将由用户垂直滚动。这是 UITable 视图的标准行为,您也可以使用 UI 集合视图。但是,应用还必须支持捏合缩放。当您在桌子上捏合缩放时,所有线条应该会压扁在一起。当你伸展时,所有的线都应该分开。

在我的概念证明中,单个细胞没有被调整大小,它们只是被重新定位得更近或更远。这是有意的:我不认为这对验证这个想法的可行性至关重要。

以下是显示当前应用程序看起来如何缩小和放大的屏幕截图:

我正在使用带有自定义UIColletionViewLayout子类的UIColletionViewLayout。布局将UIColletionViewCells定位在屏幕中间一个漂亮的摇摆正弦波中。每个UIColletionViewCell只是UILabel的容器,该UILabel保存indexPath行。

< code > UICollectionView layout 子类有一个参数,用于设置它向< code>UICollectionView描述的每个单元格之间的垂直间距,调整该参数可以根据需要垂直挤压或拉伸表格。

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

如果不进一步考虑,缩放将从内容的顶部开始,而不是在触摸手势的中心附近。UICollectionViewcontentOffset“属性在夹持期间进行调整,以提供此功能

姿势识别器还需要适应夹持时发生的拖拽。这也可以通过更改UICollectionViewcontentOffset来处理。一些附加代码允许触摸手势的中心点随着手指被添加到手势/从手势移除而改变。

请注意,< code>UICollectionView是< code>UIScrollView子类,它有自己的< code > UIPanGestureRecognizer ,与我添加的< code > uipinchgesturerecognizer 交互。我不确定这是否会造成问题。

我添加了代码来禁用<code>UICollectionView姿势识别器:应该要求获取感测识别器的图像:以使我的UIPinchGestreRecognitizer,使内置uiPanGestreConognitize器失败,但这似乎完全停止了我的pinch识别器的工作。我不知道这是我的愚蠢,还是iOS的错误。

如前所述,当前的< code > UICollectionViewCell 不会调整大小。它们只是被重新定位了。这是故意的。我认为验证这个概念并不重要。

工作位工作得很好。您可以上下拖动表格。在拖动过程中,您可以添加手指并开始捏合,然后松开手指并继续拖动,然后添加和捏合等。一切都很顺利。在原装iPhone 5上,它平稳地支持捏合和平移

当视图的顶部或底部出现在屏幕上时,如果你试图放大或缩小,一切都会变得有点疯狂。

  • 在卷轴上,视图被允许拖动,以便将其拉到可见内容之外(这是我想要的,因为这是iOS数据列表的标准行为)。
  • 但是,在缩放更改时,视图会被快速恢复,以便内容被夹在屏幕上(我不希望发生这种情况)。

这两个在捏手势的过程中互相打架,使得内容剧烈的上下闪烁(这是我绝对不希望的!).

UIColletionView的默认滚动如果您在滚动时松开,则会减速,并且当您在内容之外滚动时还会平滑地将内容反弹回来。这些目前根本没有处理。

  • 如果您在滚动时释放挤压手势,它将停止
  • 如果您使用“捏”手势滚动到内容之外,然后释放,它将停留在原来的位置,不会反弹。当您再次开始滚动时,它会将内容跳回

UICollectionView,作为一个UIScrollView应该有一个内置的uiPinchGestureRecognizer如果它被正确设置为支持缩放。我想知道我是否可以利用它,而不是拥有自己的UIPinchGestureRecognizer。我试图通过设置最小和最大刻度,并添加控制器的夹持处理程序来设置这个。然而,我并不真正理解从实现<code>视图缩放到crollView:,我应该返回什么,所以我只是用<code>[[UIView alloc]initWithFrame:[[self-collectionView]bounds]]创建了一个虚拟视图。它使滚动视图“折叠”成一行,这不是我想要的!

这是一个很长的问题,所以谢谢你阅读它。如果你能帮忙回答,那就更谢谢你了。如果我说的或补充的很多都无关紧要,我很抱歉!

//  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个答案

莫选
2023-03-14

对上述代码的一些非常小的调整已经解决了什么不起作用1

我已将以下行添加到我的UICollectionViewControllerviewDidLoad方法中:

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

我还更新了示例项目,以便视图由小圆圈组成,而不是文本标签。当您放大和缩小时,它们会调整大小。下面是它现在的样子(放大和缩小):

在缩放过程中,不会重画圆的视图,而只是从其缩放前的大小进行插值。重绘被推迟,直到缩放完成。这是放大几倍后的截图:

缩放期间的重绘发生在背景线程中会很好,这样工件就不那么明显了,但这远远超出了这个问题的范围,我也还没有研究过。

您可以在Bit Bucket上找到整个项目及其修复,这样您就可以在那里获取文件。

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

从我所读到的关于UIScrollView的内容来看,这个“修复”不应该有任何区别,而且它应该已经开始工作了。

UIScrollView不应该启用滚动,直到你给它一个实现视图的委托,因为缩放视图:,我还没有这样做。

 类似资料:
  • 我们在Google Firestore中有一个收藏。 我们是否可以在一条语句中添加一个包含数据的文档和此新文档下的子集合?

  • 尝试添加到集合时出现“Collection was modified”异常 问题出在“添加”方法上。如果我注释掉该部分,则不会引发异常。重要的是要注意,我已经尝试将foreach重写为for循环并添加“ToList()”以形成。链接。在所有情况下都会引发相同的异常。我在站点的其他部分使用这种完全相同的模式没有问题,这就是为什么这如此令人沮丧。这也适用于“创建”。问题只影响“编辑”操作。 其他相关代

  • 这是一个衍生问题,与根据颜色图设置线条颜色中给出的答案相关,其中一个很好的解决方案是根据颜色条绘制几条带有颜色的线条(见下面的代码和输出图像)。 我有一个列表,其中存储了与每个打印线关联的字符串,如下所示: 我想将这些字符串作为图例添加到绘图右上角的一个框中(第一个字符串对应于第一条绘制线,依此类推)。我怎么能这样做? 如果有必要,我可以不使用,但我需要保留颜色栏以及与之相关的每一行的颜色。 代码

  • 问题内容: 我希望有人可以帮助我。我试图允许用户捏UIImageView(允许最大和最小级别)上的缩放。但是由于某种原因,它无法正常工作。图像会稍微放大,然后反弹。谢谢。 这是变焦功能 问题答案: 我决定将imageView添加到UIScrollView中。它允许用户缩放和平移。这是我使用的代码。 为了设置最大/最小缩放,我使用了: 这是其余的代码。 我也必须添加它 Swift 3及以上功能原型

  • 我正在尝试使用android studio中的Firestore制作一个课程添加系统。 当用户添加一个课程时,它将被添加到Fi还原中,并且在该课程集合中会有一个学生和教师集合。 但我不知道怎么做。 如果我为学生和教师集合编写代码,它会添加两个不同的集合,但我希望在一个课程集合中有两个集合,学生和教师。 我该怎么做呢? 我分享我写的代码。 添加课程类