可以禁用UIPickerView的滚动声音吗?

11

我想禁用UIPickerView在向上或向下滚动时生成的讨厌的点击声。有没有办法做到这一点?我想为选择器视图落在每个项目上播放短声音,但内置声音会破坏它。

我知道可以通过在iPhone/iPod设置中关闭键盘声音来全局关闭选择器声音。但是否有一种编程方式可以实现这一点?

非常感谢任何帮助!

谢谢

8个回答

7

我一直在处理一个UIPickerView声音问题,虽然这只是部分与原始问题相关,但我发布问题/解决方案在这里,因为这个主题仍然出现在我的搜索结果中,所以我认为任何处于同样困境的人可能也会来到这里...

我需要初始化一个UIPickerView来从保存的数据中恢复当前选定的行。简单吧?在viewDidLoad中,只需调用UIPickerView的selectRow:inComponent:animated方法:

[myPicker selectRow:currentRowIndex inComponent:0 animated:NO];

这段代码按预期工作,但有一个副作用是会产生点击声音,好像用户滚动了控件一样。点击声仅在设备上运行时发生(而不是模拟器),且只在装有iOS 3.x的设备上发生(我测试了3.1.3和3.2)。这显然是iOS中的一个BUG,在iOS 4.0之后得到了修复。但如果你需要针对第一代 iPhone,你只能使用存在此问题的iOS 3.1.3。
我与苹果DTS讨论了这个问题,但他们无法建议任何解决方法,除了升级到4.0。我询问他们是否会例外并允许使用上述未经文件化的setSoundEnabled(实际上可解决问题)。答案是:“没有例外”。
经过一些额外的侦探工作,我发现可以通过暂时将UIPickerView从父视图中删除,调用selectRow,然后重新将其添加到父视图中来防止声音的发生。例如,在viewDidLoad中:
UIView *superview = [myPicker superview];
[myPicker removeFromSuperview];

[myPicker reloadAllComponents];
[myPicker selectRow:currentRowIndex inComponent:0 animated:NO];

[superview addSubview:myPicker];

这样可以消除多余的点击声,而不使用未记录/私有API,因此应该通过苹果的审批流程。

太棒了!我已经尝试很长时间来解决这个问题了。 - adamsiton
这个很好用,但是你不能给轮子添加动画效果。我尝试启用了动画,但改变视图层次结构会导致动画失效。 - bugloaf

5

在App Store上使用这个特定的未公开API已经一年了,但最终苹果还是要求我将其从我的应用中删除。对于音频应用程序来说,那该死的点击声非常令人沮丧。最好的建议是与用户分享,在“设置”应用程序下可以全局禁用选择器音效,只需将“键盘点击”设置为“关闭”。我还强烈建议访问https://bugreport.apple.com/并为UIPickerView提交错误报告,因为当播放选择器的点击声时,它可能会导致音频应用程序出现失真。


2

我认识的某人说他上周通过了App Store审核:

// Hide private API call from Apple static analyzer
SEL sse = NSSelectorFromString([NSString stringWithFormat:@"%@%@%@", @"set",@"Sounds",@"Enabled:"]);
if ([UIPickerView instancesRespondToSelector:sse]) {
    IMP sseimp = [UIPickerView instanceMethodForSelector:sse];
    sseimp(self.thePicker, sse, NO);
}

1
你的示例代码写得非常具有未来安全性,但我不确定为了绕过苹果的检查而混淆代码是否是一个好主意。我担心故意试图规避他们的API检查可能会受到严厉的惩罚。 - John Stephen

2
他们刚刚拒绝了我的一个应用程序,因为使用了未记录的API...这是其中之一。

1
也许这不是针对这个特定问题的答案,但我遇到了类似的问题-设置datePicker的minimumDate,我想在没有烦人的“点击”声的情况下设置它。经过一段时间的研究,我找到了一个非常简单的解决方案:
datePickerCustomTime.minimumDate = [[NSDate date] dateByAddingTimeInterval:300]// min time to set = now + 5 min
  [datePickerCustomTime setDate:[[NSDate date] dateByAddingTimeInterval:300] animated:NO];

以下是正确的代码:NSDate *minimumDate = [[NSDate date] dateByAddingTimeInterval:300]; if ([datePickerCustomTime.date laterDate:minimumDate] == minimumDate) { [datePickerCustomTime setDate:minimumDate animated:NO]; } datePickerCustomTime.minimumDate = minimumDate; - hlfcoding

1

有一种未记录的方法(我实际上不确定它是否仍然适用于iPhone 3.0),但无论如何,这里是它。

#import <UIKit/UIKit.h>

@interface SilintUIPickerView: UIPickerView
{ }

- (void) setSoundsEnabled: (BOOL) enabled;
@end

使用这个子类替代,并调用[view setSoundsEnabled: NO]

我对最新的SDK是如何进行的很感兴趣,试一试并告诉我们。


完美运行!非常感谢!!顺便问一下,你知道苹果有多注意避免使用未记录的API吗?这个应用需要尽快上架App Store。不想因为一点小问题被拒绝和沮丧 :) - infiniteloop
顺便问一下,你知道苹果公司有多么反感未记录的API吗?我真的不知道答案,试着在SO上搜索一下,如果还没有被问过,就提出来吧。 - hhafez
他们目前会在你使用这个方法时发出警告。 - Epsilon Prime
你总是会收到警告,因为你的对象可能无法响应未记录在头文件中的消息,因为它们已经被实现但没有在头文件中公开。所以,考虑到我给出的解决方案是未记录的,这是完全可以预料的 :) - hhafez
3
由于这个特定的 API 调用,我的两个应用程序更新被拒绝了。 - Brent Priddy

1

0
我找到了一个小而快速的解决方案,请尝试以下方法。
        UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, yPickerView, VIEW_WIDTH, PICKERVIEW_HEIGHT)];
        pickerView.delegate = self;
        pickerView.dataSource = self;
        pickerView.showsSelectionIndicator = YES;
        pickerView.alpha = 0.8f;
        pickerView.tag = fieldTag;
        [pickerView selectRow:pickerViewSelectedIndex inComponent:0 animated:NO];

为selectRow:方法设置animated:NO


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接