简体   繁体   English

将触摸和手势从 UIScrollview 转发到视图

[英]Forward Touches and Gestures to Views from UIScrollview

I have some trouble with forwarding gestures and touches.我在转发手势和触摸时遇到了一些麻烦。 I played around with it quite a bit, but i cant get it working the way I want.我玩了很多,但我不能让它按照我想要的方式工作。

Basically I want to control a scrollview on a dualscreen with 2 fingers and forward everything else to the ipad-views behind a overlaying scrollview.基本上我想用 2 个手指控制双屏上的滚动视图,并将其他所有内容转发到覆盖滚动视图后面的 ipad 视图。

To be able to control the scrollview on the dualscreen I subclassed UIScrollView and added it as a overlaying view with a clear background to the ipad-screen.为了能够控制双屏上的滚动视图,我将UIScrollView子类化,并将其添加为具有清晰背景的覆盖视图到 ipad 屏幕。

Then I hooked it up with a delegate to forward its dragging and stuff to the scrollview on the dualscreen.然后我将它与一个委托连接起来,将它的拖动和内容转发到双屏上的滚动视图。 this works perfectly.这很完美。

As I wrote I want the scrollview to respond just to 2 finger-scroll, so i set it to正如我所写的,我希望滚动视图仅响应 2 个手指滚动,所以我将其设置为

ScrollView.panGestureRecognizer.minimumNumberOfTouches = 2;

But the scrollview eats up all touches and I dont get it right to forward everything else but 2 finger touches to the views behind.但是滚动视图吃掉了所有的触摸,我不正确地将其他所有内容转发到后面的视图,但 2 根手指触摸。 I think overriding the我认为覆盖

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event

must do the trick, but I don't get it right to detect the number of fingers on the screen right.必须做到这一点,但我没有正确检测屏幕上的手指数量。

I'd like to share/explain the solution to the problem.我想分享/解释问题的解决方案。 That said I also want to point out that hatfinch input led me in the right direction.也就是说,我还想指出 Hatfinch 的输入使我朝着正确的方向前进。 thank you very very much mate!非常非常感谢你!

The problem when attempting to put a view/scrollview as an overlaying toplayer is that the toplayer doesnt know about its "next responder".尝试将视图/滚动视图作为覆盖顶层时的问题在于顶层不知道其“下一个响应者”。 putting the view/scrollview as a underlaying view will solve this problem.将视图/滚动视图作为底层视图将解决这个问题。 you may need to fine tune the touch behaviour of any scrollview within that underlaying scrollview to get the behaviour right (like setting maximum number of touches)您可能需要微调该底层滚动视图中任何滚动视图的触摸行为以获得正确的行为(例如设置最大触摸次数)

The solution is to subclass a UIScrollview, override this methods override the touchesBegan: and other touch methods as follows (see user1085093 answer), and add it as underlaying view to the ipad-screen.解决方案是将 UIScrollview 子类化,覆盖此方法覆盖 touchesBegan: 和其他触摸方法如下(参见 user1085093 回答),并将其作为底层视图添加到 ipad 屏幕。

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

// If not dragging, send event to next responder
if (!self.dragging){
    [self.nextResponder touchesBegan: touches withEvent:event];
}
else{
    [super touchesBegan: touches withEvent: event];
}}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{

// If not dragging, send event to next responder
if (!self.dragging){
    [self.nextResponder touchesMoved: touches withEvent:event];
}
else{
    [super touchesMoved: touches withEvent: event];
}}


-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{

// If not dragging, send event to next responder
if (!self.dragging){
    [self.nextResponder touchesEnded: touches withEvent:event];
}
else{
    [super touchesEnded: touches withEvent: event];
}}

i did the setup of the scrollview like this:我像这样设置了滚动视图:

 TopLayerScrollView *newScrollView = [[TopLayerScrollView alloc] init];
[newScrollView setBackgroundColor:[UIColor clearColor]];
[newScrollView setFrame:self.tabBarController.view.frame];
[newScrollView setContentSize:dualScreenViewController.scrollContent.contentSize];
newScrollView.showsHorizontalScrollIndicator = NO;
newScrollView.showsVerticalScrollIndicator = NO;
newScrollView.delegate = self;
newScrollView.bounces = NO;
[newScrollView scrollsToTop];
newScrollView.panGestureRecognizer.minimumNumberOfTouches = 2;

self.topLayerScrollView = newScrollView;
[newScrollView release];

[self.tabBarController.view removeFromSuperview];
[topLayerScrollView addSubview:self.tabBarController.view];
[window addSubview:topLayerScrollView];
[topLayerScrollView bringSubviewToFront:self.tabBarController.view];

The delegate method of the underlaying scrollview:底层滚动视图的委托方法:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (scrollView.dragging || scrollView.tracking)
{
    [dualScreenViewControlleremphasized text.scrollContent setContentOffset:CGPointMake(scrollView.contentOffset.x, scrollView.contentOffset.y) animated:NO];
    self.tabBarController.view.frame = CGRectMake(scrollView.contentOffset.x, scrollView.contentOffset.y, self.tabBarController.view.frame.size.width, self.tabBarController.view.frame.size.height);
}}

This solution works great.这个解决方案效果很好。 The other solution would be to have a scrollview as an overlaying view as I first intended.另一种解决方案是将滚动视图作为我最初打算的覆盖视图。 As said the problem is to let the toplayer view know about the views(nextResponder) benath it.如上所述,问题是让顶层视图知道它下面的视图(nextResponder)。 To achive this you must sublass UIScrollview and create a UIResponder-property you must hookup either in your interface-builder file or during runtime.要实现这一点,您必须继承 UIScrollview 并创建一个 UIResponder 属性,您必须在界面构建器文件中或在运行时进行连接。 this way the overlaying scrollview will know who is the next responder.这样覆盖的滚动视图就会知道谁是下一个响应者。 please see morningstar's answer 请看晨星的回答

Unfortunately, you can't do anything with -pointInside:withEvent: here because the system decides which view the touch is in (or which views the touches are in) before it determines whether they satisfy the requirements of the gesture recogniser.不幸的是,你不能用-pointInside:withEvent:做任何事情,因为系统在确定触摸是否满足手势识别器的要求之前,先决定触摸在哪个视图(或触摸在哪个视图)。

I think your best bet here is to have the view that is currently behind the scrollview actually be the content view of the scrollview, and to move that view every time the content offset of the scroll view changes to keep it in the same position on the screen.我认为最好的办法是让当前位于滚动视图后面的视图实际上是滚动视图的内容视图,并且每次滚动视图的内容偏移量更改时移动该视图以使其保持在相同的位置屏幕。 (This sounds expensive but it's not really.) So instead of being an overlay, your scroll view is more like an underlay. (这听起来很昂贵,但实际上并非如此。)因此,您的滚动视图不是叠加层,而是更像是底层。

You may also wish to play with UIScrollView.delaysContentTouches , -[UIScrollView touchesShouldBegin:withEvent:inContentView:] , etc. to refine the behaviour.您可能还希望使用UIScrollView.delaysContentTouches-[UIScrollView touchesShouldBegin:withEvent:inContentView:]等来优化行为。

Update for Xcode 6.4, Swift 1.2 : Xcode 6.4、Swift 1.2 的更新:

I also subclassed UIScrollView :我还UIScrollView

import UIKit

class WBMScrollView: UIScrollView
{
    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent)
    {
        self.nextResponder()?.touchesBegan(touches, withEvent: event)
        super.touchesBegan(touches, withEvent: event)
    }
}

In the app main vc ViewController.swift I tested it in:在应用程序主 vc ViewController.swift我测试了它:

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
        println(" touches began")
    }

and it worked.它奏效了。 The scrollview has been added via IB and hooked up to ViewController.swift滚动视图已通过 IB 添加并连接到ViewController.swift

With my app I needed the one-finger touch events to get forwarded to the parent view controller of the scroll view while still allowing the scroll view to zoom in/out.对于我的应用程序,我需要将单指触摸事件转发到滚动视图的父视图控制器,同时仍然允许滚动视图放大/缩小。

Using the next responder did not work because I'm also adding another overlaid view which ends up becoming the next responder and stealing the touch events.使用下一个响应者不起作用,因为我还添加了另一个叠加视图,该视图最终成为下一个响应者并窃取了触摸事件。 I ended up doing something based on Tom's answer by simply passing in the parent view controller and sending touch events directly to it.我最终根据 Tom 的回答做了一些事情,只需传入父视图控制器并将触摸事件直接发送给它。 Here it is in Swift:这是在 Swift 中的:

class CustomScrollView: UIScrollView {

    var parentViewController: UIViewController?

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        parentViewController?.touchesBegan(touches, with: event)
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        parentViewController?.touchesMoved(touches, with: event)
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        parentViewController?.touchesEnded(touches, with: event)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM