UIScrollView 阻止视图控制器上的touchesBegan、touchesMoved、touchesEnded

发布于 2024-12-05 03:59:21 字数 759 浏览 1 评论 0原文

我正在视图控制器(UIViewController 的自定义子类)中处理几个 UI 组件的触摸。它具有方法 touchesBegan:withEvent:touchesMoved:withEvent:touchesEnded:withEvent:。一切正常。然后我添加了一个滚动视图(UIScrollView)作为层次结构中的顶部视图。

现在我的视图控制器上的触摸处理程序不起作用。他们不会被叫到。有趣的是,我在滚动视图中还有其他各种可以工作的 UI 组件。有些是按钮,有些是定义自己的 touchesBegan:withEvent: 等的自定义视图。唯一不起作用的是视图控制器上的触摸处理程序。

我想也许是因为滚动视图为了自己的目的而拦截这些触摸,但我对 UIScrollView 进行了子类化,只是为了看看是否可以让它工作,我总是从 touchesShouldBegin 返回 YES : withEvent:inContentView:NO 始终来自 touchesShouldCancelInContentView:。还是不行。

如果它有所不同,我的视图控制器位于选项卡栏控制器内,但我认为它不相关。

有没有人遇到过这个问题并有现成的解决方案?我的猜测是滚动视图猴子了响应者链。我可以把它弄回来吗?我想如果我想不出其他任何东西,我将使滚动视图下的顶级视图成为自定义视图并将消息转发到视图控制器,但看起来很混乱。

I am handling touches for a couple of my UI components in my view controller (custom subclass of UIViewController). It has methods touchesBegan:withEvent:, touchesMoved:withEvent:, and touchesEnded:withEvent:. It was working fine. Then I added a scroll view (UIScrollView) as the top view in the hierarchy.

Now my touch handlers on the view controller don't work. They don't get called. The interesting thing is, I have various other UI components within the scroll view that do work. Some are buttons, some are custom views that define their own touchesBegan:withEvent:, etc. The only thing that doesn't work is the touch handlers on the view controller.

I thought maybe it's because the scroll view is intercepting those touches for its own purposes, but I subclassed UIScrollView and just to see if I could get it to work I am returning YES always from touchesShouldBegin:withEvent:inContentView: and NO always from touchesShouldCancelInContentView:. Still doesn't work.

If it makes a difference my view controller is within a tab bar controller, but I don't think it's relevant.

Has anyone had this problem and have a ready solution? My guess is the scroll view monkeys up the responder chain. Can I monkey it back? I guess if I can't figure anything else out I'll make the top level view under my scroll view be a custom view and forward the messages on to the view controller, but seems kludgy.

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

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

发布评论

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

评论(5

不…忘初心 2024-12-12 03:59:21

创建 UIScrollView 类的子类并重写 TouchBegan: 和其他触摸方法,如下所示:

-(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];
   }
}

create a subclass of UIScrollView class and override the touchesBegan: and other touch methods as follows:

-(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];
   }
}
薔薇婲 2024-12-12 03:59:21

好吧,这有效,但我不确定我是否可以“摆脱它”,因为 nextResponder 不是您“鼓励”在子类中重写的 UIView 方法之一。

@interface ResponderRedirectingView : UIView {

    IBOutlet UIResponder *newNextResponder;

}

@property (nonatomic, assign) IBOutlet UIResponder *newNextResponder;

@end


@implementation ResponderRedirectingView

@synthesize newNextResponder;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

- (UIResponder *)nextResponder {
    return self.newNextResponder;
}

- (void)dealloc
{
    [super dealloc];
}

@end

然后在 Interface Builder 中,我将滚动视图的直接子视图设为其中之一,并连接其 newNextResponder 以跳过滚动视图并直接指向视图控制器。

这也有效,用这些覆盖替换 nextResponder 的覆盖:

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.newNextResponder touchesBegan:touches withEvent:event];
}

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.newNextResponder touchesMoved:touches withEvent:event];
}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.newNextResponder touchesEnded:touches withEvent:event];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.newNextResponder touchesCancelled:touches withEvent:event];
}

Well this worked, but I'm not sure I can "get away with it", since nextResponder is not one of the UIView methods you're "encouraged" to override in a subclass.

@interface ResponderRedirectingView : UIView {

    IBOutlet UIResponder *newNextResponder;

}

@property (nonatomic, assign) IBOutlet UIResponder *newNextResponder;

@end


@implementation ResponderRedirectingView

@synthesize newNextResponder;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

- (UIResponder *)nextResponder {
    return self.newNextResponder;
}

- (void)dealloc
{
    [super dealloc];
}

@end

Then in Interface Builder I made the direct subview of the scroll view one of these, and hooked up its newNextResponder to skip the scrollview and point directly to the view controller.

This works too, replacing the override of nextResponder with these overrides:

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.newNextResponder touchesBegan:touches withEvent:event];
}

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.newNextResponder touchesMoved:touches withEvent:event];
}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.newNextResponder touchesEnded:touches withEvent:event];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.newNextResponder touchesCancelled:touches withEvent:event];
}
前事休说 2024-12-12 03:59:21

“它工作得很好。然后我添加了一个滚动视图 (UIScrollView) 作为层次结构中的顶部视图。”

您的滚动视图是否位于包含项目的内容视图之上?

所有组件都应该位于滚动视图中,而不是位于滚动视图后面的视图中

"It was working fine. Then I added a scroll view (UIScrollView) as the top view in the hierarchy."

is your scrollview on top of your contentview that contains items?

all your components should be in the scrollview and not the view behind the scrollview

微凉徒眸意 2024-12-12 03:59:21

user1085093的回答对我有用。然而,一旦您移动触摸的幅度超过一小部分,它就会被解释为平移手势。

我通过改变平移手势识别器的行为来克服这个问题,因此它需要两个手指:

-(void)awakeFromNib
{
    NSArray                 *gestureRecognizers = self.gestureRecognizers;
    UIGestureRecognizer     *gestureRecognizer;

    for (gestureRecognizer in gestureRecognizers) {
        if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
            UIPanGestureRecognizer      *pgRecognizer = (UIPanGestureRecognizer*)gestureRecognizer;
            pgRecognizer.minimumNumberOfTouches = 2;
        }
    }

}

user1085093's answer worked for me. Once you move the touch more than a small amount, however, it then gets interpreted as a Pan Gesture.

I overcame this by altering the behaviour of the Pan Gesture recogniser so it requires two fingers:

-(void)awakeFromNib
{
    NSArray                 *gestureRecognizers = self.gestureRecognizers;
    UIGestureRecognizer     *gestureRecognizer;

    for (gestureRecognizer in gestureRecognizers) {
        if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
            UIPanGestureRecognizer      *pgRecognizer = (UIPanGestureRecognizer*)gestureRecognizer;
            pgRecognizer.minimumNumberOfTouches = 2;
        }
    }

}
写下不归期 2024-12-12 03:59:21

touchesBegan: 等方法将永远UIScrollView 中调用,因为它是 UIView 的子类并覆盖这些方法方法。查看可用的不同 UIScrollView 方法 此处。解决方法取决于您想要实施的内容。

The touchesBegan: etc methods will NEVER be called in a UIScrollView because it is a subclass of UIView and overrides these methods. check out the different UIScrollView methods available here. The work-around will depend on what you want to implement.

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