使用两指平移和缩放分页 UIScrollView

发布于 2024-12-13 19:12:39 字数 1349 浏览 0 评论 0原文

测试用例很容易重现:下载 Apple 的 PhotoScroller示例应用程序,并尝试对其进行调整,以便平移(在缩放图像周围以及每个图像之间)仅适用于两根手指。

pagingScrollViewimageScrollViewpanGestureRecognizer 设置为仅接受 min &最多 2 次触摸似乎是一个不错的起点,但它不起作用。它可以让您用两根手指滚动图像就可以了*,但是分页则不起作用。

我尝试了很多设置和自定义手势识别器的组合,但我有点困惑。自定义滚动视图子类是否会有任何用处,或者我可以以某种方式操纵滚动视图委托方法以使其工作?

*编辑:实际上,在这种情况下它滚动得不太好。视图不再像单次触摸那样平滑滑动...

更新:我仍在努力解决这个问题。我希望得到使用过 UIGestureRecognizerUIScrollView 的人的一些意见。

编辑

设置 ImageScrollView 类仅接受两次触摸:

- (id)initWithFrame:(CGRect)frame
{
    // ...
    // Template code
    // ...

    [self.panGestureRecognizer setMinimumNumberOfTouches:2];
    [self.panGestureRecognizer setMaximumNumberOfTouches:2];
}

PhotoViewControllerpagingScrollView 设置为仅接受两次触摸:

- (void)loadView
{
    // ...
    // Template code
    // ...

    [pagingScrollView.panGestureRecognizer setMinimumNumberOfTouches:2];
    [pagingScrollView.panGestureRecognizer setMaximumNumberOfTouches:2];
}

这些修改直接在 PhotoScroller 示例应用程序的顶部进行。我希望这些简单的更改适用于两指交互,但副作用很奇怪(如上所述)。

The test case is easily reproduced: download Apple's PhotoScroller sample app, and try to adapt it so that panning (both around a zoomed image, and between each image) only works with two fingers.

Setting the panGestureRecognizer for both the pagingScrollView and the imageScrollView to only accept a min & max of 2 touches seems like a good place to start, however it doesn't work. It lets you scroll around an image with two fingers just fine*, however paging then doesn't work.

I've tried so many combinations of settings and custom gesture recognizers, and I'm a bit stumped. Is a custom scroll view subclass going to be of any use, or can I somehow manipulate the scroll view delegate methods to make it work?

*EDIT: Actually, it doesn't scroll fine in this situation. The view no longer glides smoothly as with a single touch...

UPDATE: I'm still struggling with this one. I would appreciate some input from somebody who has played around with UIGestureRecognizers and UIScrollViews.

EDIT:

Setting the ImageScrollView class to only accept two touches:

- (id)initWithFrame:(CGRect)frame
{
    // ...
    // Template code
    // ...

    [self.panGestureRecognizer setMinimumNumberOfTouches:2];
    [self.panGestureRecognizer setMaximumNumberOfTouches:2];
}

Setting PhotoViewController's pagingScrollView to only accept two touches:

- (void)loadView
{
    // ...
    // Template code
    // ...

    [pagingScrollView.panGestureRecognizer setMinimumNumberOfTouches:2];
    [pagingScrollView.panGestureRecognizer setMaximumNumberOfTouches:2];
}

These modifications are made directly on top of the PhotoScroller sample app. I would expect these simple changes to work for two-finger interaction, however the side-effects are odd (as explained above).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

甜嗑 2024-12-20 19:12:39

看来这要么是不可能的,要么非常非常困难(即从头开始滚动你自己的滚动视图)。我使用了 Apple 技术支持事件,但他们无法提供帮助。如果有解决方案可用,我会很乐意将其标记为已接受的答案!

It would appear that this is either impossible, or very very difficult (i.e. roll your own scroll view from scratch). I used an Apple Tech support incident and they were unable to help. If a solution becomes available I'll happily mark it as the accepted answer!

苍风燃霜 2024-12-20 19:12:39

问题

UIPanGestureRecognizer位于UIScrollView底层时> (不幸的是,这也会影响 UIPageViewControllermaximumNumberOfTouches 的行为不符合预期 - minimumNumberOfTouches 但是始终正确限制下端。

当监视这些参数时,它们似乎完成了它们的工作 - 只是 UIScrollView 不尊重它们并忽略它们的值!


补救措施

您可以在我的回答中找到解决方案:

UIScrollView 仅用一根手指滚动


顺便说一句:

你的区别一根手指和手指平移之间的体验是因为您使用一根手指panGestureRecognizer。用两根手指,pinchGestureRecognizer(也可以同时平移)启动,并且您没有减速阶段,并且视图停止平移并且松开手指后立即缩放。停用 pinchGestureRecognizer,您将看到 panGestureRecognizer 接管 - 即使是两根手指 - 并且平移再次变得平滑...;-)


同步- et voilà...

完美同步 2 指滚动缩放 行为的委托回调:

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    self.pinchGestureRecognizer.enabled = NO;
}

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
    self.pinchGestureRecognizer.enabled = NO;
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    self.pinchGestureRecognizer.enabled = YES;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    self.pinchGestureRecognizer.enabled = YES;
}

- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {    
    self.panGestureRecognizer.enabled = NO;
}

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {    
    self.panGestureRecognizer.enabled = YES;
}

快速捏合开始缩放!
快速平移开始平移!

用两个新手指在屏幕上向下停止减速平移并再次开始拖动不会让笨拙的捏手势识别器接管(默认),而是平滑地进入下一个平移/减速阶段 - 就像用一根手指一样!


对于完美主义者:

将 2 根手指放在屏幕上 - 现在不要移动 - 如果您在前 0.5 秒内没有开始捏合缩放被锁定,并且仅平移可用:

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {

    if ([gestureRecognizer.view isMemberOfClass:[MY_CustomScrollView class]]) {

        NSLog(@"IN SCROLL-VIEW...");
        if (gestureRecognizer == self.pinchGestureRecognizer) {
            if (_pinchGestureLocked) {
                NSLog(@"...but TOO late for zooming...");
                return NO;
            } else {
                NSLog(@"...ZOOMING + PANNING...");
                return YES;
            }
        } else if (gestureRecognizer == self.panGestureRecognizer){
            if (gestureRecognizer.numberOfTouches > 2) {
                NSLog(@"...but TOO many touches for PANNING ONLY...");
                return NO;
            } else {
                NSLog(@"...PANNING...");
                return YES;
            }
        } else {

            NSLog(@"...NO PAN or PINCH...");
            return YES;
        }

    } else {
        NSLog(@"NOT IN SCROLL-VIEW...");
    }

    return YES;

}  

BOOL _pinchGestureLocked = NO;

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];
    _pinchGestureLocked = YES;
}

- (void) touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [super touchesCancelled:touches withEvent:event];
    _pinchGestureLocked = NO;
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    _pinchGestureLocked = NO;
}

快乐的手势识别!


PROBLEM:

When the UIPanGestureRecognizer is underlying a UIScrollView (which unfortunately does also effect UIPageViewController) the maximumNumberOfTouches is not behaving as expected - the minimumNumberOfTouches however always limits the lower end correctly.

When monitoring these parameters they seem to do their job - it's just that UIScrollView doesn't honor them and ignores their values!


REMEDY:

You can find the solution in my answer to:

UIScrollView scrolling only with one finger


BTW:

The difference you experience between one finger and two finger panning is because with one finger you are using the panGestureRecognizer. With two fingers the pinchGestureRecognizer (which can also pan at the same time) kicks in and you have no deceleration phase and the view stops panning and zooming immediately after releasing your fingers. Deactivate the pinchGestureRecognizer and you will see that the panGestureRecognizer takes over - even for two fingers - and panning is smooth again... ;-)


SIMULTANEOUSLY - et voilà...

Delegate callbacks for a perfect simultaneous 2 finger scrolling and zooming behavior:

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    self.pinchGestureRecognizer.enabled = NO;
}

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
    self.pinchGestureRecognizer.enabled = NO;
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    self.pinchGestureRecognizer.enabled = YES;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    self.pinchGestureRecognizer.enabled = YES;
}

- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {    
    self.panGestureRecognizer.enabled = NO;
}

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {    
    self.panGestureRecognizer.enabled = YES;
}

Fast pinch starts zooming!
Fast pan starts panning!

Stopping a decelerating pan with two new fingers down on the screen and start dragging again does not let the clumsy pinchGestureRecognizer take over (default) but rather smoothly go into the next pan/deceleration phase - like with one finger!


FOR PERFECTIONISTS:

Put 2 fingers on the screen and - DON'T MOVE NOW - If you don't start pinching within the first 0.5 seconds zooming gets locked and only panning is available:

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {

    if ([gestureRecognizer.view isMemberOfClass:[MY_CustomScrollView class]]) {

        NSLog(@"IN SCROLL-VIEW...");
        if (gestureRecognizer == self.pinchGestureRecognizer) {
            if (_pinchGestureLocked) {
                NSLog(@"...but TOO late for zooming...");
                return NO;
            } else {
                NSLog(@"...ZOOMING + PANNING...");
                return YES;
            }
        } else if (gestureRecognizer == self.panGestureRecognizer){
            if (gestureRecognizer.numberOfTouches > 2) {
                NSLog(@"...but TOO many touches for PANNING ONLY...");
                return NO;
            } else {
                NSLog(@"...PANNING...");
                return YES;
            }
        } else {

            NSLog(@"...NO PAN or PINCH...");
            return YES;
        }

    } else {
        NSLog(@"NOT IN SCROLL-VIEW...");
    }

    return YES;

}  

BOOL _pinchGestureLocked = NO;

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];
    _pinchGestureLocked = YES;
}

- (void) touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [super touchesCancelled:touches withEvent:event];
    _pinchGestureLocked = NO;
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    _pinchGestureLocked = NO;
}

Happy gesture-recognizing!


久夏青 2024-12-20 19:12:39

子类化似乎是解决这个问题的方法

文档指出您可以通过子类化来操纵滚动手势的处理方式。

UIScrollView 类参考

具体

子类可以覆盖
touchesShouldBegin:withEvent:inContentView:、pagingEnabled 和
TouchsShouldCancelInContentView:方法(由
滚动视图)来影响滚动视图处理滚动手势的方式。

您还应该看看这篇文章,用 UIScrollView 用两根手指滚动

Subclassing seems to be the way to go with this

The documentation states that you can manipulate how scrolling gestures are handled through subclassing.

UIScrollView Class Reference

Specifically

Subclasses can override the
touchesShouldBegin:withEvent:inContentView:, pagingEnabled, and
touchesShouldCancelInContentView: methods (which are called by the
scroll view) to affect how the scroll view handles scrolling gestures.

You should also take a look at this SO post, Scrolling with two fingers with a UIScrollView

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文