diff --git a/Shared/KBConfig.h b/Shared/KBConfig.h index 46ab8b2..f98849a 100644 --- a/Shared/KBConfig.h +++ b/Shared/KBConfig.h @@ -36,3 +36,9 @@ #ifndef KB_KEYBOARD_EXTENSION_BUNDLE_ID #define KB_KEYBOARD_EXTENSION_BUNDLE_ID @"com.keyBoardst.CustomKeyboard" #endif + +// --- 常用宏 --- +// 弱引用 self(在 block 中避免循环引用):使用处直接写 KBWeakSelf; +#ifndef KBWeakSelf +#define KBWeakSelf __weak __typeof(self) weakSelf = self; +#endif diff --git a/keyBoard.xcodeproj/project.pbxproj b/keyBoard.xcodeproj/project.pbxproj index 1e31e13..556c9fa 100644 --- a/keyBoard.xcodeproj/project.pbxproj +++ b/keyBoard.xcodeproj/project.pbxproj @@ -38,7 +38,6 @@ 04FC95D22EB1E7AE007BD342 /* MyVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95D12EB1E7AE007BD342 /* MyVC.m */; }; 04FC95D72EB1EA16007BD342 /* BaseTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95D62EB1EA16007BD342 /* BaseTableView.m */; }; 04FC95D82EB1EA16007BD342 /* BaseCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95D42EB1EA16007BD342 /* BaseCell.m */; }; - A1B2D7022EB8C00100000001 /* KBLangTestVC.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2D7012EB8C00100000001 /* KBLangTestVC.m */; }; 04FC95DD2EB202A3007BD342 /* KBGuideVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95DC2EB202A3007BD342 /* KBGuideVC.m */; }; 04FC95E52EB220B5007BD342 /* UIColor+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95E42EB220B5007BD342 /* UIColor+Extension.m */; }; 04FC95E92EB23B67007BD342 /* KBNetworkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95E72EB23B67007BD342 /* KBNetworkManager.m */; }; @@ -59,6 +58,7 @@ A1B2C4002EB4A0A100000004 /* KBAuthManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C4002EB4A0A100000002 /* KBAuthManager.m */; }; A1B2C4202EB4B7A100000001 /* KBKeyboardPermissionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C4222EB4B7A100000001 /* KBKeyboardPermissionManager.m */; }; A1B2C4212EB4B7A100000001 /* KBKeyboardPermissionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C4222EB4B7A100000001 /* KBKeyboardPermissionManager.m */; }; + A1B2D7022EB8C00100000001 /* KBLangTestVC.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2D7012EB8C00100000001 /* KBLangTestVC.m */; }; ECC9EE02174D86E8D792472F /* Pods_keyBoard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 967065BB5230E43F293B3AF9 /* Pods_keyBoard.framework */; }; /* End PBXBuildFile section */ @@ -136,8 +136,6 @@ 04FC95CB2EB1E780007BD342 /* BaseTabBarController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BaseTabBarController.m; sourceTree = ""; }; 04FC95CD2EB1E7A1007BD342 /* HomeVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HomeVC.h; sourceTree = ""; }; 04FC95CE2EB1E7A1007BD342 /* HomeVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HomeVC.m; sourceTree = ""; }; - A1B2D7002EB8C00100000001 /* KBLangTestVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBLangTestVC.h; sourceTree = ""; }; - A1B2D7012EB8C00100000001 /* KBLangTestVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBLangTestVC.m; sourceTree = ""; }; 04FC95D02EB1E7AE007BD342 /* MyVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyVC.h; sourceTree = ""; }; 04FC95D12EB1E7AE007BD342 /* MyVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyVC.m; sourceTree = ""; }; 04FC95D32EB1EA16007BD342 /* BaseCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BaseCell.h; sourceTree = ""; }; @@ -184,6 +182,8 @@ A1B2C4002EB4A0A100000002 /* KBAuthManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAuthManager.m; sourceTree = ""; }; A1B2C4222EB4B7A100000001 /* KBKeyboardPermissionManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBKeyboardPermissionManager.m; sourceTree = ""; }; A1B2C4232EB4B7A100000001 /* KBKeyboardPermissionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBKeyboardPermissionManager.h; sourceTree = ""; }; + A1B2D7002EB8C00100000001 /* KBLangTestVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBLangTestVC.h; sourceTree = ""; }; + A1B2D7012EB8C00100000001 /* KBLangTestVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBLangTestVC.m; sourceTree = ""; }; B12EC429812407B9F0E67565 /* Pods-CustomKeyboard.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CustomKeyboard.release.xcconfig"; path = "Target Support Files/Pods-CustomKeyboard/Pods-CustomKeyboard.release.xcconfig"; sourceTree = ""; }; B8CA018AB878499327504AAD /* Pods-CustomKeyboard.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CustomKeyboard.debug.xcconfig"; path = "Target Support Files/Pods-CustomKeyboard/Pods-CustomKeyboard.debug.xcconfig"; sourceTree = ""; }; F67DDBD716E4E616D8CC2C9C /* Pods-keyBoard.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-keyBoard.debug.xcconfig"; path = "Target Support Files/Pods-keyBoard/Pods-keyBoard.debug.xcconfig"; sourceTree = ""; }; @@ -358,8 +358,6 @@ 04FC95B92EB1E3B1007BD342 /* VC */ = { isa = PBXGroup; children = ( - 04FC95CA2EB1E780007BD342 /* BaseTabBarController.h */, - 04FC95CB2EB1E780007BD342 /* BaseTabBarController.m */, ); path = VC; sourceTree = ""; @@ -446,6 +444,8 @@ children = ( 04FC95C72EB1E4C9007BD342 /* BaseNavigationController.h */, 04FC95C82EB1E4C9007BD342 /* BaseNavigationController.m */, + 04FC95CA2EB1E780007BD342 /* BaseTabBarController.h */, + 04FC95CB2EB1E780007BD342 /* BaseTabBarController.m */, ); path = VC; sourceTree = ""; diff --git a/keyBoard/Assets.xcassets/back_black_icon.imageset/Contents.json b/keyBoard/Assets.xcassets/back_black_icon.imageset/Contents.json new file mode 100644 index 0000000..79099b2 --- /dev/null +++ b/keyBoard/Assets.xcassets/back_black_icon.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "back@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "back@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/keyBoard/Assets.xcassets/back_black_icon.imageset/back@2x.png b/keyBoard/Assets.xcassets/back_black_icon.imageset/back@2x.png new file mode 100644 index 0000000..a41e24c Binary files /dev/null and b/keyBoard/Assets.xcassets/back_black_icon.imageset/back@2x.png differ diff --git a/keyBoard/Assets.xcassets/back_black_icon.imageset/back@3x.png b/keyBoard/Assets.xcassets/back_black_icon.imageset/back@3x.png new file mode 100644 index 0000000..0e61428 Binary files /dev/null and b/keyBoard/Assets.xcassets/back_black_icon.imageset/back@3x.png differ diff --git a/keyBoard/Class/Main/VC/BaseTabBarController.h b/keyBoard/Class/Base/VC/BaseTabBarController.h similarity index 100% rename from keyBoard/Class/Main/VC/BaseTabBarController.h rename to keyBoard/Class/Base/VC/BaseTabBarController.h diff --git a/keyBoard/Class/Main/VC/BaseTabBarController.m b/keyBoard/Class/Base/VC/BaseTabBarController.m similarity index 100% rename from keyBoard/Class/Main/VC/BaseTabBarController.m rename to keyBoard/Class/Base/VC/BaseTabBarController.m diff --git a/keyBoard/Class/Guard/VC/KBGuideVC.m b/keyBoard/Class/Guard/VC/KBGuideVC.m index df000a8..b3ba9dd 100644 --- a/keyBoard/Class/Guard/VC/KBGuideVC.m +++ b/keyBoard/Class/Guard/VC/KBGuideVC.m @@ -27,6 +27,8 @@ typedef NS_ENUM(NSInteger, KBGuideItemType) { @property (nonatomic, strong) UITapGestureRecognizer *bgTap;// 点击空白收起键盘 @property (nonatomic, strong) NSMutableArray *items; // 数据源 [{type, text}] +/// 权限引导页作为子控制器(用于“同时隐藏”) +@property (nonatomic, strong, nullable) KBPermissionViewController *permVC; @end @@ -80,6 +82,9 @@ typedef NS_ENUM(NSInteger, KBGuideItemType) { // 监听应用回到前台/变为活跃:用于从设置返回时再次校验权限 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(kb_checkKeyboardPermission) name:UIApplicationDidBecomeActiveNotification object:nil]; + + // 提前创建并铺满权限引导页(默认隐藏),避免后续显示时出现布局进场感 + [self kb_preparePermissionOverlayIfNeeded]; } - (void)dealloc { @@ -101,23 +106,26 @@ typedef NS_ENUM(NSInteger, KBGuideItemType) { KBFARecord fa = [mgr lastKnownFullAccess]; BOOL needGuide = (!enabled) || (enabled && fa == KBFARecordDenied); - UIViewController *top = [UIViewController kb_topMostViewController]; - if (needGuide) { - if (![top isKindOfClass:[KBPermissionViewController class]]) { - KBPermissionViewController *guide = [KBPermissionViewController new]; - guide.modalPresentationStyle = UIModalPresentationFullScreen; - __weak typeof(self) weakSelf = self; - guide.onBack = ^{ - // 用户主动点击“返回”时,同步退出引导页 - [weakSelf.navigationController popViewControllerAnimated:YES]; - }; - [top presentViewController:guide animated:YES completion:nil]; - } - } else { - if ([top isKindOfClass:[KBPermissionViewController class]]) { - [top dismissViewControllerAnimated:YES completion:nil]; - } - } + [self kb_preparePermissionOverlayIfNeeded]; + BOOL show = needGuide; + [UIView performWithoutAnimation:^{ + self.permVC.view.hidden = !show; + }]; +} + +/// 提前创建权限引导页覆盖层(仅一次) +- (void)kb_preparePermissionOverlayIfNeeded { + if (self.permVC) return; + KBPermissionViewController *guide = [KBPermissionViewController new]; + guide.modalPresentationStyle = UIModalPresentationFullScreen; // 仅用于内部布局,不会真正 present + KBWeakSelf; + guide.backHandler = ^{ [weakSelf.navigationController popViewControllerAnimated:YES]; }; + self.permVC = guide; + [self addChildViewController:guide]; + [self.view addSubview:guide.view]; + [guide.view mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.view); }]; + [guide didMoveToParentViewController:self]; + guide.view.hidden = YES; // 初始隐藏 } - (void)kb_didTapBackground { diff --git a/keyBoard/VC/KBPermissionViewController.h b/keyBoard/VC/KBPermissionViewController.h index c425135..d3d91e0 100644 --- a/keyBoard/VC/KBPermissionViewController.h +++ b/keyBoard/VC/KBPermissionViewController.h @@ -12,7 +12,8 @@ NS_ASSUME_NONNULL_BEGIN @interface KBPermissionViewController : UIViewController /// 点击页面左上角“返回”时回调。用于让调用方(如 KBGuideVC)一起退出等自定义行为。 -@property (nonatomic, copy, nullable) void (^onBack)(void); +/// 注意:避免与按钮 action `onBack` 重名,故命名为 backHandler。 +@property (nonatomic, copy, nullable) void (^backHandler)(void); @end diff --git a/keyBoard/VC/KBPermissionViewController.m b/keyBoard/VC/KBPermissionViewController.m index aec5744..dc1bb40 100644 --- a/keyBoard/VC/KBPermissionViewController.m +++ b/keyBoard/VC/KBPermissionViewController.m @@ -78,11 +78,28 @@ #pragma mark - Actions - (void)onBack { - // 先关闭自身,再让调用方按需处理(例如同时退出引导页) - void (^handler)(void) = self.onBack; - [self dismissViewControllerAnimated:YES completion:^{ - if (handler) handler(); - }]; + // 支持两种展示方式: + // 1) 作为子控制器嵌入(无 presentingViewController)→ 交由回调让父 VC 处理(通常 pop) + // 2) 作为模态弹出 → 按原策略先 pop 再 dismiss + UIViewController *presenter = self.presentingViewController; + if (!presenter) { + if (self.backHandler) self.backHandler(); + return; + } + + UINavigationController *nav = nil; + if ([presenter isKindOfClass:UINavigationController.class]) { + nav = (UINavigationController *)presenter; + } else if (presenter.navigationController) { + nav = presenter.navigationController; + } + + if (nav) { + [nav popViewControllerAnimated:NO]; + [nav dismissViewControllerAnimated:YES completion:^{ if (self.backHandler) self.backHandler(); }]; + } else { + [self dismissViewControllerAnimated:YES completion:^{ if (self.backHandler) self.backHandler(); }]; + } } - (void)openSettings {