响应UIPickerView中的touchesBegan而不是UIView

时间:2009-02-20 00:02:31

标签: objective-c iphone cocoa-touch uipickerview

我有一个UIPickerView,在不使用时会逐渐消失为20%alpha。我希望用户能够触摸选择器并将其淡入。

如果我在主视图上放置touchesBegan方法,我可以使用它,但这仅在用户触摸View时才有效。我尝试对UIPickerView进行子类化并在那里使用touchesBegan,但它没有用。

我猜测它与Responder链有关,但似乎无法解决这个问题。

5 个答案:

答案 0 :(得分:10)

我一直在寻找这个问题的解决方案超过一周。即使你的问题超过一年,我也会回答你的问题,希望能帮到别人。

很抱歉,如果我的语言不是非常技术性,但我对Objective-C和iPhone开发很新。

子类化UIpickerView是正确的方法。但是你要覆盖- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event方法。无论何时触摸屏幕,都会调用此方法,并返回将对触摸作出反应的视图。换句话说,将调用touchesBegan:withEvent:方法的视图。

UIPickerView有9个子视图!在UIPickerView类中,实现- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event将不会返回self(这意味着您在子类中编写的touchesBegan:withEvent:将不会被调用)但会返回一个子视图,完全是索引处的视图4(一个名为UIPickerTable的未记录的子类)。

诀窍是让- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event方法返回self,以便您可以控制touchesBegan:withEvent:touchesMoved:withEvent:touchesEnded:withEvent:方法。

在这些方法中,为了保持UIPickerView的标准功能,你必须记得再次调用它们,但是在UIPickerTable子视图上。

我希望这是有道理的。我现在无法编写代码,只要我在家,我就会编辑这个答案并添加一些代码。

答案 1 :(得分:8)

以下是一些可以满足您需求的代码:

@interface TouchDetectionView : UIPickerView {

}
- (UIView *)getNextResponderView:(NSSet *)touches withEvent:(UIEvent *)event;
@end
@implementation TouchDetectionView

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
    [hitTestView touchesBegan:touches withEvent:event];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
    [hitTestView touchesMoved:touches withEvent:event];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
    [hitTestView touchesEnded:touches withEvent:event];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
    [hitTestView touchesCancelled:touches withEvent:event];
}

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    return self;
}

- (UIView *)getNextResponderView:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch * touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];
    UIView * hitTestView = [super hitTest:point withEvent:event];

    return ( hitTestView == self ) ? nil : hitTestView;
}

答案 2 :(得分:1)

上述两个答案都非常有用,但我在UIScrollView中嵌套了UIPickerView。当GUI存在时,我也在屏幕上的其他地方继续渲染。问题是UIPickerView在以下情况下不会完全更新:点击未选择的行,移动选择器以使两行跨越选择区域,或者拖动一行但手指滑动到UIPickerView之外。然后,直到UIScrollView被移动,选择器立即更新。这个结果太丑了。

问题的原因:我的持续渲染是让UIPickerView的动画无法获得完成所需的CPU周期,从而显示正确的当前选择。我的解决方案 - 工作原理 - 是这样的:在UIPickerView的touchesEnded:withEvent:中,执行一些操作暂停我的渲染。这是代码:

#import "SubUIPickerView.h"

@implementation SubUIPickerView

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

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

- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
    [singleton set_secondsPauseRendering:0.5f];  // <-- my code to pause rendering

    [pickerTable touchesEnded:touches withEvent:event];
}

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

- (UIView*) hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
    if (CGRectContainsPoint(self.bounds, point))
    {
        if (pickerTable == nil)
        {
            int nSubviews = self.subviews.count;
            for (int i = 0; i < nSubviews; ++i)
            {
                UIView* view = (UIView*) [self.subviews objectAtIndex:i];
                if ([view isKindOfClass:NSClassFromString(@"UIPickerTable")])
                {
                    pickerTable = (UIPickerTable*) view;
                    break;
                }
            }
        }
        return self;    // i.e., *WE* will respond to the hit and pass it to UIPickerTable, above.
    }
    return [super hitTest:point withEvent:event];
}

@end

然后是标题,SubUIPickerView.h:

@class UIPickerTable;

@interface SubUIPickerView : UIPickerView
{
    UIPickerTable*  pickerTable;
}

@end
像我说的那样,这很有效。渲染暂停另外1/2秒(当您滑动UIScrollView时它已经暂停)允许UIPickerView动画完成。使用NSClassFromString()意味着您没有使用任何未记录的API。与Responder链混淆是没有必要的。感谢checcco和Tylerc230帮我提出了自己的解决方案!

答案 3 :(得分:1)

找不到最新,更简单的解决方案,因此我索要一些解决方案。创建了一个在选择器视图上延伸的不可见按钮。使用“ Touch Down”识别器将该按钮连接到我的父UIView。现在可以添加任何功能,当有人触摸选择器视图时,我碰巧需要一个随机选择计时器来使它失效。不是很优雅,但是可以。

答案 4 :(得分:0)

将父视图的canCancelContentTouches和delayedContentTouches设置为NO,这对我有用