gpt4 book ai didi

iphone - 处理子 UIScrollView 中的触摸事件

转载 作者:行者123 更新时间:2023-12-03 18:44:06 25 4
gpt4 key购买 nike

我在 UIScrollView 中显示一系列图像。我非常想复制“照片”应用程序。

我当前的架构是:

  • 父 UIScrollView 的内容大小足以容纳 x 页数以及图像之间的边距的一些额外空间。
  • 每个图像都包含在 UIImageView 中。
  • 每个 UIImageView 都包含在其自己的 UIScrollview 中,这些 UIScrollview 是父 UIScrollView 的 subview 。

    所以我基本上在父 UIScrollView 中有一行 UIScrollView。

    父 UIScrollView 启用了分页,因此我可以毫无问题地从一个页面滚动到另一个页面。

    问题是如何无缝地平移放大的图像。我已经重写了 viewForZoomingInScrollView 方法,以在用户捏合/捏合时返回适当的 UIImageView。如果缩放比例大于 1,我已重写 scrollViewDidEndZooming 方法,将父 View 的 canCancelContentTouches 属性设置为 NO

    因此用户可以平移图像。但是,在将触摸事件发送到 subview 之前,他们必须按住手指一会儿,以克服父 ScrollView 的小延迟。此外,一旦用户平移一张图像,当用户到达当前图像的边界时,下一张/上一张图像不会进入可视区域。

    有什么想法吗?

    谢谢。

  • 最佳答案

    耶!我尝试仅使用一个 UIScrollView 来解决该问题,并且我认为我找到了解决方案。

    在用户开始缩放之前(在 viewForZoomingInScrollView: 中),我将 ScrollView 切换到缩放模式(删除所有附加页面,重置内容大小和偏移量)。当用户缩小到比例 1.00(在 scrollViewDidEndZooming:withView:atScale: 中)时,我切换回分页 View (添加所有页面,调整内容大小和偏移量)。

    下面是一个简单 View Controller 的代码,它就是这样做的。此示例在三个大型 UIImageView 之间切换、缩放和平移。

    请注意,只需一个具有少量功能的 View Controller 即可,无需子类化 UIScrollView 或其他内容。

    typedef enum {
    ScrollViewModeNotInitialized, // view has just been loaded
    ScrollViewModePaging, // fully zoomed out, swiping enabled
    ScrollViewModeZooming, // zoomed in, panning enabled
    ScrollViewModeAnimatingFullZoomOut, // fully zoomed out, animations not yet finished
    ScrollViewModeInTransition, // during the call to setPagingMode to ignore scrollViewDidScroll events
    } ScrollViewMode;

    @interface ScrollingMadnessViewController : UIViewController <UIScrollViewDelegate> {
    UIScrollView *scrollView;
    NSArray *pageViews;
    NSUInteger currentPage;
    ScrollViewMode scrollViewMode;
    }

    @end

    @implementation ScrollingMadnessViewController

    - (void)setPagingMode {
    NSLog(@"setPagingMode");
    if (scrollViewMode != ScrollViewModeAnimatingFullZoomOut && scrollViewMode != ScrollViewModeNotInitialized)
    return; // setPagingMode is called after a delay, so something might have changed since it was scheduled
    scrollViewMode = ScrollViewModeInTransition; // to ignore scrollViewDidScroll when setting contentOffset

    // reposition pages side by side, add them back to the view
    CGSize pageSize = scrollView.frame.size;

    NSUInteger page = 0;
    for (UIView *view in pageViews) {
    if (!view.superview)
    [scrollView addSubview:view];
    view.frame = CGRectMake(pageSize.width * page++, 0, pageSize.width, pageSize.height);
    }

    scrollView.pagingEnabled = YES;
    scrollView.showsVerticalScrollIndicator = scrollView.showsHorizontalScrollIndicator = NO;
    scrollView.contentSize = CGSizeMake(pageSize.width * [pageViews count], pageSize.height);
    scrollView.contentOffset = CGPointMake(pageSize.width * currentPage, 0);

    scrollViewMode = ScrollViewModePaging;
    }

    - (void)setZoomingMode {
    NSLog(@"setZoomingMode");
    scrollViewMode = ScrollViewModeInTransition; // to ignore scrollViewDidScroll when setting contentOffset

    CGSize pageSize = scrollView.frame.size;

    // hide all pages besides the current one
    NSUInteger page = 0;
    for (UIView *view in pageViews)
    if (currentPage != page++)
    [view removeFromSuperview];

    // move the current page to (0, 0), as if no other pages ever existed
    [[pageViews objectAtIndex:currentPage] setFrame:CGRectMake(0, 0, pageSize.width, pageSize.height)];

    scrollView.pagingEnabled = NO;
    scrollView.showsVerticalScrollIndicator = scrollView.showsHorizontalScrollIndicator = YES;
    scrollView.contentSize = pageSize;
    scrollView.contentOffset = CGPointZero;

    scrollViewMode = ScrollViewModeZooming;
    }

    - (void)loadView {
    CGRect frame = [UIScreen mainScreen].applicationFrame;
    scrollView = [[UIScrollView alloc] initWithFrame:frame];
    scrollView.delegate = self;
    scrollView.maximumZoomScale = 2.0f;
    scrollView.minimumZoomScale = 1.0f;

    UIImageView *imageView1 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"red.png"]];
    UIImageView *imageView2 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"green.png"]];
    UIImageView *imageView3 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"yellow-blue.png"]];

    // in a real app, you most likely want to have an array of view controllers, not views;
    // also should be instantiating those views and view controllers lazily
    pageViews = [[NSArray alloc] initWithObjects:imageView1, imageView2, imageView3, nil];

    self.view = scrollView;
    }

    - (void)setCurrentPage:(NSUInteger)page {
    if (page == currentPage)
    return;
    currentPage = page;
    // in a real app, this would be a good place to instantiate more view controllers -- see SDK examples
    }

    - (void)viewDidLoad {
    scrollViewMode = ScrollViewModeNotInitialized;
    [self setPagingMode];
    }

    - (void)viewDidUnload {
    [pageViews release]; // need to release all page views here; our array is created in loadView, so just releasing it
    pageViews = nil;
    }

    - (void)scrollViewDidScroll:(UIScrollView *)aScrollView {
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(setPagingMode) object:nil];
    CGPoint offset = scrollView.contentOffset;
    NSLog(@"scrollViewDidScroll: (%f, %f)", offset.x, offset.y);
    if (scrollViewMode == ScrollViewModeAnimatingFullZoomOut && ABS(offset.x) < 1e-5 && ABS(offset.y) < 1e-5)
    // bouncing is still possible (and actually happened for me), so wait a bit more to be sure
    [self performSelector:@selector(setPagingMode) withObject:nil afterDelay:0.1];
    else if (scrollViewMode == ScrollViewModePaging)
    [self setCurrentPage:roundf(scrollView.contentOffset.x / scrollView.frame.size.width)];
    }

    - (UIView *)viewForZoomingInScrollView:(UIScrollView *)aScrollView {
    if (scrollViewMode != ScrollViewModeZooming)
    [self setZoomingMode];
    return [pageViews objectAtIndex:currentPage];
    }

    - (void)scrollViewDidEndZooming:(UIScrollView *)aScrollView withView:(UIView *)view atScale:(float)scale {
    NSLog(@"scrollViewDidEndZooming: scale = %f", scale);
    if (fabsf(scale - 1.0) < 1e-5) {
    if (scrollView.zoomBouncing)
    NSLog(@"scrollViewDidEndZooming, but zoomBouncing is still true!");

    // cannot call setPagingMode now because scrollView will bounce after a call to this method, resetting contentOffset to (0, 0)
    scrollViewMode = ScrollViewModeAnimatingFullZoomOut;
    // however sometimes bouncing will not take place
    [self performSelector:@selector(setPagingMode) withObject:nil afterDelay:0.2];
    }
    }

    @end

    可运行的示例项目位于 http://github.com/andreyvit/ScrollingMadness/ (如果您不使用 Git,只需单击那里的“下载”按钮)。那里有一个自述文件,解释了为什么这样编写代码。

    (示例项目还说明了如何以编程方式缩放 ScrollView ,并具有封装了该解决方案的 ZoomScrollView 类。它是一个简洁的类,但不是此技巧所必需的。如果您想要一个不包含 ScrollView 的示例,使用 ZoomScrollView,返回提交历史记录中的一些提交。)

    附注为了完整起见,TTScrollView - UIScrollView 从头开始​​重新实现。它是伟大而著名的Three20 library的一部分。我不喜欢用户的感觉,但它确实使分页/滚动/缩放的实现变得非常简单。

    P.P.S。 Apple 真正的照片应用程序具有预 SDK 代码并使用预 SDK 类。人们可以在 PhotoLibrary 框架内发现两个从 UIScrollView 的 SDK 前变体派生的类,但是并不能立即清楚它们的作用(而且它们做了很多事情)。我很容易相信这种效果在 SDK 之前的时代很难实现。

    关于iphone - 处理子 UIScrollView 中的触摸事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/241152/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com