6

我有一个 UIPickerView 在不使用时会淡出到 20% 的 alpha。我希望用户能够触摸选择器并将其淡入。

如果我在主视图上放置一个 touchesBegan 方法,我可以让它工作,但这仅在用户触摸视图时有效。我尝试对 UIPickerView 进行子类化并在其中设置 touchesBegan,但它没有用。

我猜这与响应者链有关,但似乎无法解决。

4

5 回答 5

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 子视图上再次调用它们。

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

于 2010-07-15T08:59:17.763 回答
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;
}
于 2011-05-07T00:24:55.013 回答
1

以上两个答案都非常有帮助,但我有一个 UIPickerView 嵌套在 UIScrollView 中。当 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。没有必要弄乱响应者链。感谢 checcco 和 Tylerc230 帮助我提出自己的解决方案!

于 2011-07-06T05:34:45.030 回答
1

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

于 2013-01-04T16:57:35.137 回答
1

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

于 2020-02-16T05:20:21.690 回答