【问题标题】:Play keyboard click sound in a collection view controller在集合视图控制器中播放键盘点击声音
【发布时间】:2017-01-04 23:03:35
【问题描述】:

我创建了 UICollectionViewController 的子类,用作 UITextView 中的自定义 inputAccessoryViewControllerhttps://developer.apple.com/reference/uikit/uiresponder/1621124-inputaccessoryviewcontroller

当您使用 playInputClick 在集合视图中点击一个单元格时,我想播放键盘点击声音。 https://developer.apple.com/reference/uikit/uidevice/1620050-playinputclick

我不知道如何让它在集合视图中工作。它适用于像这样的简单视图,使用 UITextViewinputAccessoryView 属性,但我不确定在集合视图控制器层次结构中子类化哪个视图以播放键盘点击声音。

@interface KeyboardClickView : UIView <UIInputViewAudioFeedback>
@end

@implementation KeyboardClickView
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if(self)
    {
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];
        [self addGestureRecognizer:tap];
    }
    return self;
}

- (void)tap:(id)sender
{
    [[UIDevice currentDevice] playInputClick];
}

- (BOOL)enableInputClicksWhenVisible
{
    return YES;
}
@end

@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{   
    _inputAccessoryView = [[KeyboardClickView alloc] initWithFrame:CGRectMake(0, 0, 0, 50)];
    _inputAccessoryView.backgroundColor = [UIColor redColor];
    [[UITextView appearance] setInputAccessoryView:_inputAccessoryView];

    // ...
}
@end

我也知道您可以使用AudioServicesPlaySystemSound(1104) 播放键盘点击声音,但如果他们禁用了键盘点击声音,这不尊重用户的设置。

【问题讨论】:

    标签: ios objective-c uicollectionview


    【解决方案1】:

    UIViewController 中使用playInputClick 的好处:

    虚拟输入附件视图:

    @interface Clicker : UIView <UIInputViewAudioFeedback>
    
    @end
    
    @implementation Clicker
    
    - (BOOL)enableInputClicksWhenVisible
    {
        return YES;
    }
    
    @end
    

    带输入附件视图的视图:

    @interface ControllerView : UIView
    
    @end
    
    @implementation ControllerView
    
    - (BOOL)canBecomeFirstResponder
    {
        return YES;
    }
    
    - (UIView *)inputAccessoryView
    {
        return [[Clicker alloc] init];
    }
    
    @end
    

    带有自定义视图的视图控制器:

    @implementation ViewController
    
    - (void)loadView
    {
        self.view = [[ControllerView alloc] init];
    }
    
    - (void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
        [self.view becomeFirstResponder];
    }
    
    - (void)viewWillDisappear:(BOOL)animated
    {
        [super viewWillDisappear:animated];
        [self.view resignFirstResponder];
    }
    
    @end
    

    当响应者对象成为第一响应者和inputView时 (或 inputAccessoryView) 不为零,UIKit 将输入视图动画化为 放置在父视图下方(或将输入附件视图附加到 输入视图的顶部)。

    由于Clicker 视图的高度为零,并且符合UIInputViewAudioFeedback 协议在ViewController 中启用[[UIDevice currentDevice] playInputClick] 功能,因此没有视觉后果。

    here 中查找响应者链,在here 中查找输入附件视图。

    【讨论】:

    • 感谢您的回答。我不清楚Clicker 的使用以及为什么要从另一个视图创建此视图。我尝试在我的视图控制器中实现额外的becomeFirstResponderresignFirstResponder,但我仍然没有播放点击声音。
    • 请注意 playInputClick 服从 Settings / Sounds / Keyboard Clicks 选项。另请注意,Xcode
    • @bteapot 为什么需要Clicker 视图? ControllerView 也可以实现UIInputViewAudioFeedback 协议和方法。我试过这个,但点击声音不会这样工作。你能解释一下为什么Clicker 视图是必要的吗?
    • UIInputViewAudioFeedback 协议的@BrunoBieri 文档指出,enableInputClicksWhenVisible 属性是使自定义输入或键盘附件视图能够播放标准键盘输入点击的属性。这意味着链中ViewController.view -> ControllerView.inputAccessoryView -> Clicker 恰好是Clicker——作为vc视图的输入附件视图——必须采用UIInputViewAudioFeedback协议。
    • 不,行不通。 UIKit 专门管理从input... 方法返回的视图的生命周期。当键盘显示时,它将该视图添加到键盘窗口的视图层次结构中,并在键盘隐藏时删除。因此,如果您返回 self - 您的视图将至少从其父视图中删除,以及任何其他未定义的后果。它必须是两个不同的视图——它们同时出现在屏幕上,每个都有自己的父级和框架 (illustration)。
    【解决方案2】:

    不使用UICollectionViewController,而是将KeyboardClickView 定义为UICollectionView 的子类并将其放在UIViewController 上。

    @interface KeyboardClickView : UICollectionView <UIInputViewAudioFeedback>
    
    - (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout {
        self = [super initWithFrame:frame collectionViewLayout:layout];
    
        // existing implementation
    

    新的视图控制器可能如下所示:

    @interface KeyboardClickViewController: UIViewController <UICollectionViewDelegate, UICollectionViewDataSource>
    @property (nonatomic, strong) KeyboardClickView *clickView;
    @end
    
    @implementation KeyboardClickViewController
    
    -(void)viewDidLoad {
        [super viewDidLoad];
    
        self.clickView = [[KeyboardClickView alloc] initWithFrame:self.view.bounds collectionViewLayout:[UICollectionViewFlowLayout new]];
        self.clickView.delegate = self;
        self.clickView.dataSource = self;
        [self.view addSubview:self.clickView];
    }
    
    // existing UICollectionViewController logic
    
    @end
    

    这使您可以从UIView 而不是UIViewController 调用playInputClick

    【讨论】:

    • 我刚试过这个,但它对我不起作用。我在我的子类集合视图中创建了一个-playClick 函数,然后我从具有集合视图委托的子类视图控制器中的-didSelectItemAtIndexPath 调用此函数。它正在调用该函数,但没有点击声音。
    • 也只是为了澄清playClick调用[[UIDevice currentDevice] playInputClick]
    【解决方案3】:

    这是 bteapot 答案的 Swift 4.2(iOS 11 和 12)版本。

    private class ClickerDummyView: UIView, UIInputViewAudioFeedback {
        var enableInputClicksWhenVisible: Bool { return true }
    }
    
    private class ClickerControllerView: UIView {
        override var canBecomeFirstResponder: Bool {
            return true
        }
    
        override var inputAccessoryView: UIView? {
            return ClickerDummyView()
        }
    }
    
    
    class ClickingViewController: UIViewController {
    
        override func loadView() {
            self.view = ClickerControllerView()
        }
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            view.becomeFirstResponder()
        }
    
        override func viewWillDisappear(_ animated: Bool) {
            super.viewWillDisappear(animated)
            view.resignFirstResponder()
        }
    }
    

    现在在需要时从ClickingViewController 类中调用UIDevice.current.playInputClick(),将触发键盘点击声音(相对于系统设置)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-14
      • 1970-01-01
      • 2019-04-27
      • 2019-05-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多