当前位置:  开发笔记 > 编程语言 > 正文

处理子UIScrollView中的触摸事件

如何解决《处理子UIScrollView中的触摸事件》经验,为你挑选了1个好方法。

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

我目前的架构是:

与内容大小父UIScrollView的是足够宽X页+一些额外的空间,在图像之间的利润数字.

每个图像都包含在UIImageView中.

每一个的UIImageView包含在它自己的UIScrollView然后将它们父的UIScrollView的子视图中.

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

父UIScrollView启用了分页,因此我可以在页面之间滚动而不会出现任何问题.

问题是如何无缝平移放大的图像.我已经覆盖了viewForZoomingInScrollView方法,以返回适当的UIImageView当用户捏输入/输出. 如果缩放比例大于1,我已经覆盖了scrollViewDidEndZooming将父视图的canCancelContentTouches属性设置为的方法NO.

因此用户可以平移图像.但是,在将触摸事件发送到子视图之前,他们必须将手指放下一会儿才能超过父滚动视图的小延迟.此外,一旦用户在一个图像平移,下/预防和图像不当用户已经达到了当前图像的边界进入可视区域.

有任何想法吗?

谢谢.

Andrey Taran.. 5

好极了!我试图用一个UIScrollView解决问题,我想我找到了一个解决方案.

在用户开始缩放(in viewForZoomingInScrollView:)之前,我将滚动视图切换到缩放模式(删除所有其他页面,重置内容大小和偏移).当用户缩小到1.00(in scrollViewDidEndZooming:withView:atScale:)时,我切换回分页视图(添加所有页面,调整内容大小和偏移).

这是一个简单的视图控制器的代码,它就是这样做的.此示例在三个大型UIImageView之间切换,缩放和平移.

请注意,只需要一个具有少量功能的视图控制器,无需子类化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  {
    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,只需单击那里的"下载"按钮).那里有一个自述文件,解释了代码编写原理的原因.

(该示例项目还说明了如何以编程方式缩放滚动视图,并且具有封装解决方案的ZoomScrollView类.它是一个整洁的类,但不需要此技巧.如果您想要一个不使用ZoomScrollView的示例,在提交历史记录中返回一些提交.)

PS为了完整起见,有TTScrollView - UIScrollView从头开始重新实现.它是着名的Three20图书馆的一部分.我不喜欢它对用户的感觉,但它确实使得实现分页/滚动/缩放变得简单.

PPS Apple的真实照片应用程序具有SDK前代码并使用SDK之前的类.人们可以在PhotoLibrary框架内发现从UIScrollView的SDK前版本变体派生的两个类,但是不清楚他们做了什么(并且他们做了很多).我很容易相信这种效果在SDK之前的版本中更难以实现.



1> Andrey Taran..:

好极了!我试图用一个UIScrollView解决问题,我想我找到了一个解决方案.

在用户开始缩放(in viewForZoomingInScrollView:)之前,我将滚动视图切换到缩放模式(删除所有其他页面,重置内容大小和偏移).当用户缩小到1.00(in scrollViewDidEndZooming:withView:atScale:)时,我切换回分页视图(添加所有页面,调整内容大小和偏移).

这是一个简单的视图控制器的代码,它就是这样做的.此示例在三个大型UIImageView之间切换,缩放和平移.

请注意,只需要一个具有少量功能的视图控制器,无需子类化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  {
    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,只需单击那里的"下载"按钮).那里有一个自述文件,解释了代码编写原理的原因.

(该示例项目还说明了如何以编程方式缩放滚动视图,并且具有封装解决方案的ZoomScrollView类.它是一个整洁的类,但不需要此技巧.如果您想要一个不使用ZoomScrollView的示例,在提交历史记录中返回一些提交.)

PS为了完整起见,有TTScrollView - UIScrollView从头开始重新实现.它是着名的Three20图书馆的一部分.我不喜欢它对用户的感觉,但它确实使得实现分页/滚动/缩放变得简单.

PPS Apple的真实照片应用程序具有SDK前代码并使用SDK之前的类.人们可以在PhotoLibrary框架内发现从UIScrollView的SDK前版本变体派生的两个类,但是不清楚他们做了什么(并且他们做了很多).我很容易相信这种效果在SDK之前的版本中更难以实现.

推荐阅读
oDavid_仔o_880
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有