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



我创建了一个UICollectionViewController的子类,它被用作UITextView中的自定义inputAccessoryViewController。https://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)播放键盘点击声音,但如果他们禁用键盘点击声音,这就不尊重用户的设置。

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

当responder对象成为第一个responder和inputView(或inputAccessoryView)不是nil, UIKit将输入视图动画到放置在父视图下面(或将输入附件视图附加到输入视图的顶部)。

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

查看这里的响应器链和这里的输入附件视图

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

@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

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

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(),键盘点击声音将被触发(相对于系统设置)。

最新更新