【问题标题】:Change the FirstResponder更改第一响应者
【发布时间】:2011-09-03 10:39:00
【问题描述】:

大家好。 我在触摸处理和 UIResponder 方面遇到了一点问题。

我的目标是管理一次触摸(移动)以与不同的视图进行交互。

我向我的 UIImageView 添加了一个手势识别器,它向我的 customViewController 发送一条简单的消息。它在点击的 UIImageView 上分配并显示自定义视图(继承 UIButton)。

我将能够(无需松开最初的手指点击)将触摸动作发送到我新分配的自定义按钮。

我的 UIImageView 似乎吞下了我的触摸,所以我的新 Button 感觉不到手指的移动。 我试图让第一响应者辞职,但似乎没有效果。

我的自定义按钮工作得很好,但前提是我释放第一次点击,然后再次点击新的显示按钮。

有什么建议吗? 提前谢谢你。

这里有一些代码:

在我的 viewController 中,我将一个 longPressGestureRecognizer 附加到我的 profileImageView 中,它在 profileImageView 周围绘制了一个圆形按钮。

-(void)showMenu:(UIGestureRecognizer*)gesture {
    [profileImageView removeGestureRecognizer:gesture];
    [profileImageView setUserInteractionEnabled:NO];

    ConcentricRadius radius;
    radius.externalRadius = 75;
    radius.internalRadius = 45;

    GTCircularButton *circularMenu = [[[GTCircularButton alloc] initWithImage:[UIImage imageNamed:@"radio.png"] highlightedImage:[UIImage imageNamed:@"radio_selected.png"] radius:radius] autorelease];
    [circularMenu setTag:kCircularTagControllerCircularMenu];
    [circularMenu setCenter:[profileImageView center]];

    // Buttons' frames will be set up by the circularMenu
    UIButton *button1 = [[[UIButton alloc] init] autorelease];
    UIButton *button2 = [[[UIButton alloc] init] autorelease];
    UIButton *button3 = [[[UIButton alloc] init] autorelease];
    UIButton *button4 = [[[UIButton alloc] init] autorelease];

    [circularMenu setButtons:[NSArray arrayWithObjects:button1, button2, button3, button4, nil]];

    //[[self view] addSubview:circularMenu];
    [[self view] insertSubview:circularMenu belowSubview:profileImageView];
}

现在我使用 touchMoved 方法手动处理 circularMenu 内的 touchEvent。

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    CGPoint touchLocation = [(UITouch*)[touches anyObject] locationInView:self];

    for (UIView *aSubview in _roundButtons) {
        if ([aSubview isKindOfClass:[UIButton class]]) {
            UIButton *aButton = (UIButton*)aSubview;
            CGPoint buttonTouchPointConverted =  [aButton convertPoint:touchLocation toView:aButton];

            if (CGRectContainsPoint([[aButton layer] frame], buttonTouchPointConverted)) {
                [self rotateHighlightImage:aButton];
            }
        }
    }
}

目标始终是处理手势识别器的结束并将触摸事件传递给创建的新实例,而无需将手指从屏幕上抬起。

有什么想法吗?

PD:如果我在我的按钮(1、2、3 和 4)上使用 addTarget:action:forControlEvents:,我会使用 touchMoved 手动处理触摸,检测到 touchEvent 的按钮会吞下它并使其他按钮无法感觉到触摸在它们上方移动。

【问题讨论】:

  • 创建一个触摸事件并插入到事件队列中?

标签: iphone uiresponder


【解决方案1】:

好吧,伙计们,我终于解决了我的问题,我达到了我的目标!

我发现了真正的问题。 只需 GestureRecognizer 处理触摸事件,直到其状态设置为 UIGestureRecognizerStateEnded,因此 GestureRecognizer 会吞下触摸事件,而没有机会将触摸事件发送到响应者链的其余部分。

我再次阅读 UIGestureRecognizer 类参考,发现该属性已启用。

为了解决我的问题,当手势启动目标方法时我做的第一件事是将启用的手势设置为 NO。这样手势释放立即触摸控制和touchMoved就可以执行了。

希望这对某人有所帮助。

以上修改代码:

-(void)showMenu:(UIGestureRecognizer*)gesture {
    [gesture setEnabled:NO];          // This is the key line of my problem!!
    [profileImageView removeGestureRecognizer:gesture];
    [profileImageView setUserInteractionEnabled:NO];

    ConcentricRadius radius;
    radius.externalRadius = 75;
    radius.internalRadius = 45;

    GTCircularButton *circularMenu = [[[GTCircularButton alloc] initWithImage:[UIImage imageNamed:@"radio.png"] highlightedImage:[UIImage imageNamed:@"radio_selected.png"] radius:radius] autorelease];
    [circularMenu setTag:kCircularTagControllerCircularMenu];
    [circularMenu setCenter:[profileImageView center]];

    // Buttons' frames will be set up by the circularMenu
    UIButton *button1 = [[[UIButton alloc] init] autorelease];
    UIButton *button2 = [[[UIButton alloc] init] autorelease];
    UIButton *button3 = [[[UIButton alloc] init] autorelease];
    UIButton *button4 = [[[UIButton alloc] init] autorelease];

    [circularMenu setButtons:[NSArray arrayWithObjects:button1, button2, button3, button4, nil]];

    //[[self view] addSubview:circularMenu];
    [[self view] insertSubview:circularMenu belowSubview:profileImageView];
}

【讨论】:

    【解决方案2】:

    您的touchesEnded:withEvent: 必须与您的touchesMoved:withEvent: 相同,只是它必须调用可能与控制事件Touch Up Inside 事件相关联的方法。

    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
        CGPoint touchLocation = [(UITouch*)[touches anyObject] locationInView:self];
    
        for (UIView *aSubview in _roundButtons) {
            if ([aSubview isKindOfClass:[UIButton class]]) {
                UIButton *aButton = (UIButton*)aSubview;
                CGPoint buttonTouchPointConverted =  [aButton convertPoint:touchLocation toView:aButton];
    
                if (CGRectContainsPoint([[aButton layer] frame], buttonTouchPointConverted)) {
                    [aButton sendActionsForControlEvents:UIControlEventTouchUpInside];
                    return;
                }
            }
        }
    }
    

    我所做的唯一更改是让按钮为我们发送控制事件。

    原答案

    在处理您的手势的函数中,执行此操作,

    if ( gesture.state == UIGestureRecognizerStateEnded ) {
        CGPoint point = [gesture locationInView:button];
        if ( CGRectContainsPoint(button.bounds, point) ) {
            [button sendActionsForControlEvents:UIControlEventTouchUpInside];
        }
    }
    

    这会检查手势的最后一次触摸是否在按钮内部,并向其所有目标发送 touch up inside 事件。

    【讨论】:

    • 我无法使用 sendActionsForControlEvents,因为手势识别器已附加到 UIImageView。我会在几分钟后发布代码。非常感谢!
    • 我在图像视图对象上测试了这段代码。它奏效了,所以我有点惊讶。
    • sendActionsForControlEvents 是 UIControl 类中的一个方法,因此我不能在 UIImageView 上使用此方法,因为它不是 UIControl 的父级。您在一个按钮对象上使用 sendActionsForControlEvents,该对象可能是一个 UIButton,它是一个 UIControl。也许我可以将 profileImageView 更改为 UIButton 而不是 UIImageView 并尝试您的代码。
    • @Gabriele 我已更改答案以包含可以帮助您转发的代码。
    • 谢谢 Deepak,但它仍然无法正常工作,原因很简单。我在 touchMoved 的最开始设置了一个断点,只是程序没有通过它。只有当我抬起手指然后再次点击移动手指时,我才能看到程序在断点处停止。我很确定我需要使用 UIResponder 类来管理代码。明天我将再次阅读苹果指南以尝试实现我的目标。非常感谢。
    【解决方案3】:

    我认为您应该在创建按钮后更改视图的设置。例如。

    myImageView.userInteractionEnabled = NO;
    

    这样,UIImageView 就不会再听触摸了。

    让我知道它是否有效。

    【讨论】:

    • 能否请您发布您创建的代码并将按钮添加为子视图?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多