我创建了一个UICollectionViewController的子类,它被用作UITextView
中的自定义inputAccessoryViewController
。https://developer.apple.com/reference/uikit/uiresponder/1621124-inputaccessoryviewcontroller
我想在使用playInputClick点击集合视图中的单元格时播放键盘单击声音。https://developer.apple.com/reference/uikit/uidevice/1620050-playinputclick
我不知道如何让这个工作在一个集合视图。它适用于像这样使用UITextView
的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
我也知道你可以使用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()
,键盘点击声音将被触发(相对于系统设置)。