简体   繁体   English

在集合视图控制器中播放键盘点击声音

[英]Play keyboard click sound in a collection view controller

I created a subclass of a UICollectionViewController that is used as the custom inputAccessoryViewController in a UITextView .我创建了一个 UICollectionViewController 的子类,用作UITextView的自定义inputAccessoryViewController https://developer.apple.com/reference/uikit/uiresponder/1621124-inputaccessoryviewcontroller https://developer.apple.com/reference/uikit/uiresponder/1621124-inputaccessoryviewcontroller

I want to play the keyboard click sound when you tap a cell in the collection view using playInputClick.当您使用 playInputClick 在集合视图中点击一个单元格时,我想播放键盘点击声音。 https://developer.apple.com/reference/uikit/uidevice/1620050-playinputclick https://developer.apple.com/reference/uikit/uidevice/1620050-playinputclick

I cannot figure out how to get this to work in a collection view.我不知道如何让它在集合视图中工作。 It works for a simple view like this using the inputAccessoryView property of a UITextView but I'm not sure what view to subclass in the collection view controller hierarchy to get the keyboard click sound to play.它使用UITextViewinputAccessoryView属性适用于这样的简单视图,但我不确定要在集合视图控制器层次结构inputAccessoryView类化哪个视图才能播放键盘单击声音。

@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

I'm also aware that you can play the keyboard click sound using AudioServicesPlaySystemSound(1104) but this doesn't respect the user's settings if they have the keyboard click sounds disabled.我也知道您可以使用AudioServicesPlaySystemSound(1104)播放键盘点击声音,但是如果他们禁用了键盘点击声音,这不尊重用户的设置。

To use the benefits of playInputClick in UIViewController :要在UIViewController使用playInputClick的好处:

Dummy input accessory view:虚拟输入附件视图:

@interface Clicker : UIView <UIInputViewAudioFeedback>

@end

@implementation Clicker

- (BOOL)enableInputClicksWhenVisible
{
    return YES;
}

@end

View with input accessory view:带有输入附件视图的视图:

@interface ControllerView : UIView

@end

@implementation ControllerView

- (BOOL)canBecomeFirstResponder
{
    return YES;
}

- (UIView *)inputAccessoryView
{
    return [[Clicker alloc] init];
}

@end

View Controller with custom view:带有自定义视图的视图控制器:

@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

When the responder object becomes the first responder and inputView (or inputAccessoryView) is not nil, UIKit animates the input view into place below the parent view (or attaches the input accessory view to the top of the input view).当响应者对象成为第一响应者并且 inputView(或 inputAccessoryView)不为 nil 时,UIKit 将输入视图动画化到父视图下方(或将输入附件视图附加到输入视图顶部)。

There is no visual consequences since the height of Clicker view is zero, and conforming to UIInputViewAudioFeedback protocol enables [[UIDevice currentDevice] playInputClick] functionality within ViewController .由于Clicker视图的高度为零,因此没有视觉效果,并且符合UIInputViewAudioFeedback协议在ViewController启用[[UIDevice currentDevice] playInputClick]功能。

Look here for responder chains and here for input accessory views. 在此处查看响应者链, 在此处查看输入附件视图。

Instead of using a UICollectionViewController , define KeyboardClickView as a subclass of UICollectionView and place it on a UIViewController .不要使用UICollectionViewController ,而是将KeyboardClickView定义为UICollectionView的子类并将其放置在UIViewController

@interface KeyboardClickView : UICollectionView <UIInputViewAudioFeedback>

- (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout {
    self = [super initWithFrame:frame collectionViewLayout:layout];

    // existing implementation

The new view controller could look something like this:新的视图控制器可能如下所示:

@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

This allows you to make the call to playInputClick from a UIView instead of a UIViewController .这允许您从UIView而不是UIViewController调用playInputClick

Here's a working Swift 4.2 (iOS 11 and 12) version of bteapot's answer.这是 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()
    }
}

Now call UIDevice.current.playInputClick() from within the ClickingViewController class whenever needed and the keyboard click sound will be triggered (with respect to system settings).现在在需要时从ClickingViewController类中调用UIDevice.current.playInputClick()并且将触发键盘点击声音(关于系统设置)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM