1
This commit is contained in:
@@ -29,6 +29,8 @@ typedef NS_ENUM(NSInteger, KBGuideItemType) {
|
||||
@property (nonatomic, strong) NSMutableArray<NSDictionary *> *items; // 数据源 [{type, text}]
|
||||
/// 权限引导页作为子控制器(用于“同时隐藏”)
|
||||
@property (nonatomic, strong, nullable) KBPermissionViewController *permVC;
|
||||
/// 记录上一次的输入法标识,避免重复提示
|
||||
@property (nonatomic, copy, nullable) NSString *kb_lastInputModeIdentifier;
|
||||
|
||||
@end
|
||||
|
||||
@@ -45,8 +47,9 @@ typedef NS_ENUM(NSInteger, KBGuideItemType) {
|
||||
[self.inputBar addSubview:self.textField];
|
||||
|
||||
[self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.left.right.equalTo(self.view);
|
||||
make.left.right.equalTo(self.view);
|
||||
make.bottom.equalTo(self.view);
|
||||
make.top.mas_equalTo(KB_NAV_TOTAL_HEIGHT);
|
||||
}];
|
||||
|
||||
[self.inputBar mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
@@ -83,8 +86,17 @@ typedef NS_ENUM(NSInteger, KBGuideItemType) {
|
||||
// 监听应用回到前台/变为活跃:用于从设置返回时再次校验权限
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(kb_checkKeyboardPermission) name:UIApplicationDidBecomeActiveNotification object:nil];
|
||||
|
||||
// 监听输入法切换(系统未公开常量,使用字符串名以兼容不同系统版本)
|
||||
NSArray<NSString *> *modeNotiNames = @[ @"UITextInputCurrentInputModeDidChangeNotification",
|
||||
@"UITextInputCurrentInputModeDidChange" ];
|
||||
for (NSString *n in modeNotiNames) {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(kb_inputModeDidChange:) name:n object:nil];
|
||||
}
|
||||
|
||||
// 提前创建并铺满权限引导页(默认隐藏),避免后续显示时出现布局进场感
|
||||
[self kb_preparePermissionOverlayIfNeeded];
|
||||
|
||||
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
@@ -95,6 +107,19 @@ typedef NS_ENUM(NSInteger, KBGuideItemType) {
|
||||
[super viewWillAppear:animated];
|
||||
// 每次进入页面都校验一次(包括从其它页面返回)
|
||||
[self kb_checkKeyboardPermission];
|
||||
// 仅在“权限已满足/引导未显示”时再去判断当前键盘是否为自家扩展
|
||||
BOOL permissionReady = (self.permVC && self.permVC.view.hidden == YES);
|
||||
if (permissionReady) {
|
||||
// 不要在未成为第一响应者时立即判断,避免拿不到 textInputMode 导致“误判不是自己的键盘”
|
||||
if (![self.textField isFirstResponder]) {
|
||||
[self.textField becomeFirstResponder];
|
||||
}
|
||||
// 尝试在下一轮主线程循环评估一次;若键盘尚未完全弹出,会在
|
||||
// UIKeyboardWillChangeFrame 或输入法切换通知里再次评估
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self kb_evaluateCurrentInputModeAndNotifyIfNeeded];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// 校验键盘权限:
|
||||
@@ -179,6 +204,8 @@ typedef NS_ENUM(NSInteger, KBGuideItemType) {
|
||||
// self.tableView.scrollIndicatorInsets = inset;
|
||||
} completion:^(BOOL finished) {
|
||||
[self scrollToBottomAnimated:YES];
|
||||
// 键盘位置变化后,尝试检测是否发生了输入法切换
|
||||
[self kb_evaluateCurrentInputModeAndNotifyIfNeeded];
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -191,6 +218,58 @@ typedef NS_ENUM(NSInteger, KBGuideItemType) {
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Keyboard Detection
|
||||
|
||||
/// 判断当前激活在本页输入框上的系统键盘是否为我方扩展键盘
|
||||
/// 说明:
|
||||
/// - 依赖 `UITextField.textInputMode` 获取当前输入法;
|
||||
/// - 通过 KVC 读取其 `identifier`(系统未公开的属性),再与扩展的 bundle id 比较;
|
||||
/// - 仅在 `textField` 为第一响应者、且软键盘弹出时才有意义。
|
||||
- (BOOL)kb_isMyExtensionKeyboardSelected {
|
||||
UITextInputMode *mode = self.textField.textInputMode;
|
||||
if (!mode) { return NO; }
|
||||
NSString *identifier = nil;
|
||||
@try {
|
||||
// 私有字段:仅用于判断是否为自家扩展;与 App 内其它用法保持一致
|
||||
identifier = [mode valueForKey:@"identifier"];
|
||||
} @catch (__unused NSException *e) {
|
||||
identifier = nil;
|
||||
}
|
||||
if (![identifier isKindOfClass:[NSString class]]) { return NO; }
|
||||
return [identifier rangeOfString:KB_KEYBOARD_EXTENSION_BUNDLE_ID].location != NSNotFound;
|
||||
}
|
||||
|
||||
- (void)kb_inputModeDidChange:(NSNotification *)note {
|
||||
// 用户从地球键切换输入法时调用
|
||||
[self kb_evaluateCurrentInputModeAndNotifyIfNeeded];
|
||||
}
|
||||
|
||||
/// 读取当前输入法 identifier(可能为 nil)
|
||||
- (NSString *)kb_currentInputModeIdentifier {
|
||||
UITextInputMode *mode = self.textField.textInputMode;
|
||||
if (!mode) return nil;
|
||||
NSString *identifier = nil;
|
||||
@try { identifier = [mode valueForKey:@"identifier"]; } @catch (__unused NSException *e) { identifier = nil; }
|
||||
return [identifier isKindOfClass:NSString.class] ? identifier : nil;
|
||||
}
|
||||
|
||||
/// 若输入法发生变化,则立刻提示是否为自家键盘
|
||||
- (void)kb_evaluateCurrentInputModeAndNotifyIfNeeded {
|
||||
// 仅在本页输入框处于编辑状态时判断,避免误触发
|
||||
if (![self.textField isFirstResponder]) return;
|
||||
|
||||
// 若权限引导正在显示,不弹提示(未满足前置条件)
|
||||
if (self.permVC && self.permVC.view.hidden == NO) return;
|
||||
|
||||
NSString *currId = [self kb_currentInputModeIdentifier];
|
||||
if (currId.length == 0) return;
|
||||
if ([self.kb_lastInputModeIdentifier isEqualToString:currId]) return; // 去抖
|
||||
self.kb_lastInputModeIdentifier = currId;
|
||||
|
||||
BOOL isMine = [currId rangeOfString:KB_KEYBOARD_EXTENSION_BUNDLE_ID].location != NSNotFound;
|
||||
[KBHUD showInfo:(isMine ? @"是自己的键盘" : @"❎不是自己的键盘")];
|
||||
}
|
||||
|
||||
#pragma mark - UITableView
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
|
||||
Reference in New Issue
Block a user