diff --git a/CustomKeyboard/KeyboardViewController.m b/CustomKeyboard/KeyboardViewController.m index 91832a5..e8f08f1 100644 --- a/CustomKeyboard/KeyboardViewController.m +++ b/CustomKeyboard/KeyboardViewController.m @@ -6,16 +6,18 @@ // #import "KeyboardViewController.h" -#import "KBToolBar.h" -#import "KBKeyboardView.h" +#import "KBKeyBoardMainView.h" + #import "KBKey.h" +#import "KBFunctionView.h" +#import "Masonry.h" static CGFloat KEYBOARDHEIGHT = 256; -@interface KeyboardViewController () +@interface KeyboardViewController () @property (nonatomic, strong) UIButton *nextKeyboardButton; // 系统“下一个键盘”按钮(可选) -@property (nonatomic, strong) KBToolBar *topBar; -@property (nonatomic, strong) KBKeyboardView *keyboardView; +@property (nonatomic, strong) KBKeyBoardMainView *keyBoardMainView; // 功能面板视图(点击工具栏第0个时显示) +@property (nonatomic, strong) KBFunctionView *functionView; // 功能面板视图(点击工具栏第0个时显示) @end @implementation KeyboardViewController @@ -28,7 +30,6 @@ static CGFloat KEYBOARDHEIGHT = 256; - (void)viewDidLoad { [super viewDidLoad]; - [self setupUI]; } @@ -36,45 +37,47 @@ static CGFloat KEYBOARDHEIGHT = 256; - (void)setupUI { // 固定键盘整体高度 [self.view.heightAnchor constraintEqualToConstant:KEYBOARDHEIGHT].active = YES; - - // 顶部栏 - self.topBar = [[KBToolBar alloc] init]; - self.topBar.delegate = self; - [self.view addSubview:self.topBar]; - [self.topBar mas_makeConstraints:^(MASConstraintMaker *make) { + // 预置功能面板(默认隐藏),与键盘区域共享相同布局 + self.functionView.hidden = YES; + [self.view addSubview:self.functionView]; + [self.functionView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self.view); - make.top.equalTo(self.view.mas_top).offset(6); - make.height.mas_equalTo(40); + make.top.equalTo(self.view).offset(4); + make.bottom.equalTo(self.view.mas_bottom).offset(-4); }]; - - // 键盘区域 - self.keyboardView = [[KBKeyboardView alloc] init]; - self.keyboardView.delegate = self; - [self.view addSubview:self.keyboardView]; - [self.keyboardView mas_makeConstraints:^(MASConstraintMaker *make) { + + self.keyBoardMainView.delegate = self; + [self.view addSubview:self.keyBoardMainView]; + [self.keyBoardMainView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self.view); - make.top.equalTo(self.topBar.mas_bottom).offset(4); + make.top.equalTo(self.view).offset(4); make.bottom.equalTo(self.view.mas_bottom).offset(-4); }]; } -#pragma mark - KBToolBarDelegate -- (void)toolBar:(KBToolBar *)toolBar didTapActionAtIndex:(NSInteger)index { - // 可根据业务透传或处理。示例:插入占位标记 [A1]..[A4] -// NSString *placeholder = [NSString stringWithFormat:@"[A%ld]", (long)index+1]; +#pragma mark - Private +/// 切换显示功能面板/键盘主视图 +- (void)showFunctionPanel:(BOOL)show { + // 简单显隐切换,复用相同的布局区域 + self.functionView.hidden = !show; + self.keyBoardMainView.hidden = show; + + // 可选:把当前显示的视图置顶,避免层级遮挡 + if (show) { + [self.view bringSubviewToFront:self.functionView]; + } else { + [self.view bringSubviewToFront:self.keyBoardMainView]; + } } -- (void)toolBarDidTapSettings:(KBToolBar *)toolBar { - // 这里示例仅插入一个标记。 - [self.textDocumentProxy insertText:@"[settings]"]; -} -#pragma mark - KBKeyboardViewDelegate -- (void)keyboardView:(KBKeyboardView *)keyboard didTapKey:(KBKey *)key { +// MARK: - KBKeyBoardMainViewDelegate + +- (void)keyBoardMainView:(KBKeyBoardMainView *)keyBoardMainView didTapKey:(KBKey *)key { switch (key.type) { case KBKeyTypeCharacter: [self.textDocumentProxy insertText:key.output ?: key.title ?: @""]; break; @@ -84,20 +87,41 @@ static CGFloat KEYBOARDHEIGHT = 256; [self.textDocumentProxy insertText:@" "]; break; case KBKeyTypeReturn: [self.textDocumentProxy insertText:@"\n"]; break; - case KBKeyTypeModeChange: { - // 切换 字母 <-> 数字 布局 - keyboard.layoutStyle = (keyboard.layoutStyle == KBKeyboardLayoutStyleLetters) ? KBKeyboardLayoutStyleNumbers : KBKeyboardLayoutStyleLetters; - [keyboard reloadKeys]; - } break; case KBKeyTypeGlobe: [self advanceToNextInputMode]; break; case KBKeyTypeCustom: - // 自定义占位:切换语言或其它操作 [self.textDocumentProxy insertText:@"[lang]"]; break; + case KBKeyTypeModeChange: case KBKeyTypeShift: - // Shift 已在 KBKeyboardView 内部处理 + // 这些已在 KBKeyBoardMainView/KBKeyboardView 内部处理 break; } } +- (void)keyBoardMainView:(KBKeyBoardMainView *)keyBoardMainView didTapToolActionAtIndex:(NSInteger)index { + // 符合你的要求:由控制器来切换面板 + if (index == 0) { + [self showFunctionPanel:YES]; + } else { + [self showFunctionPanel:NO]; + } +} + +#pragma mark - lazy +- (KBKeyBoardMainView *)keyBoardMainView{ + if (!_keyBoardMainView) { + _keyBoardMainView = [[KBKeyBoardMainView alloc] init]; + } + return _keyBoardMainView; +} + +- (KBFunctionView *)functionView{ + if (!_functionView) { + _functionView = [[KBFunctionView alloc] init]; + } + return _functionView; +} + @end + + diff --git a/CustomKeyboard/View/KBFunctionView.h b/CustomKeyboard/View/KBFunctionView.h index 5f9aea1..ebe7247 100644 --- a/CustomKeyboard/View/KBFunctionView.h +++ b/CustomKeyboard/View/KBFunctionView.h @@ -6,13 +6,21 @@ // #import -@class KBFunctionBarView, KBFunctionPasteView; +@class KBFunctionBarView, KBFunctionPasteView,KBFunctionView; + +@protocol KBFunctionViewDelegate +@optional +- (void)functionView:(KBFunctionView *_Nullable)functionView didTapToolActionAtIndex:(NSInteger)index; +@end NS_ASSUME_NONNULL_BEGIN /// 整个功能面板视图:顶部Bar + 粘贴区 + 标签列表 + 右侧操作按钮 @interface KBFunctionView : UIView +@property (nonatomic, weak) id delegate; + + @property (nonatomic, strong, readonly) UICollectionView *collectionView; // 话术分类/标签列表 @property (nonatomic, strong, readonly) NSArray *items; // 简单数据源(演示用) diff --git a/CustomKeyboard/View/KBKeyBoardMainView.h b/CustomKeyboard/View/KBKeyBoardMainView.h new file mode 100644 index 0000000..c6a9305 --- /dev/null +++ b/CustomKeyboard/View/KBKeyBoardMainView.h @@ -0,0 +1,30 @@ +// +// KBKeyBoardMainView.h +// CustomKeyboard +// +// Created by Mac on 2025/10/28. +// + +#import + + +@class KBKeyBoardMainView, KBKey; + +NS_ASSUME_NONNULL_BEGIN + +@protocol KBKeyBoardMainViewDelegate +@optional +/// 键被点击的回调 +- (void)keyBoardMainView:(KBKeyBoardMainView *)keyBoardMainView didTapKey:(KBKey *)key; + +/// 顶部工具栏按钮点击回调(index: 0~3)。 +/// 需求:当 index == 0 时,由外部(KeyboardViewController)决定是否切换到功能面板 +- (void)keyBoardMainView:(KBKeyBoardMainView *)keyBoardMainView didTapToolActionAtIndex:(NSInteger)index; +@end + +@interface KBKeyBoardMainView : UIView +@property (nonatomic, weak) id delegate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/CustomKeyboard/View/KBKeyBoardMainView.m b/CustomKeyboard/View/KBKeyBoardMainView.m new file mode 100644 index 0000000..db6fc25 --- /dev/null +++ b/CustomKeyboard/View/KBKeyBoardMainView.m @@ -0,0 +1,115 @@ +// +// KBKeyBoardMainView.m +// CustomKeyboard +// +// Created by Mac on 2025/10/28. +// + +#import "KBKeyBoardMainView.h" +#import "KBToolBar.h" +#import "KBKeyboardView.h" +#import "KBFunctionView.h" +#import "KBKey.h" +#import "Masonry.h" + +@interface KBKeyBoardMainView () +@property (nonatomic, strong) KBToolBar *topBar; +@property (nonatomic, strong) KBKeyboardView *keyboardView; +// 注意:功能面板的展示/隐藏由外部控制器决定,此处不再直接管理显隐 +@end +@implementation KBKeyBoardMainView + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + self.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1.0]; + // 顶部栏 + self.topBar = [[KBToolBar alloc] init]; + self.topBar.delegate = self; + [self addSubview:self.topBar]; + [self.topBar mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(self); + make.top.equalTo(self.mas_top).offset(6); + make.height.mas_equalTo(40); + }]; + + // 键盘区域 + self.keyboardView = [[KBKeyboardView alloc] init]; + self.keyboardView.delegate = self; + [self addSubview:self.keyboardView]; + [self.keyboardView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(self); + make.top.equalTo(self.topBar.mas_bottom).offset(4); + make.bottom.equalTo(self.mas_bottom).offset(-4); + }]; + + // 功能面板切换交由外部控制器处理;此处不直接创建/管理 + + } + return self; +} + + +#pragma mark - KBToolBarDelegate + +- (void)toolBar:(KBToolBar *)toolBar didTapActionAtIndex:(NSInteger)index { + // 将事件抛给外部控制器,由其决定是否切换到功能面板 + if ([self.delegate respondsToSelector:@selector(keyBoardMainView:didTapToolActionAtIndex:)]) { + [self.delegate keyBoardMainView:self didTapToolActionAtIndex:index]; + } +} + +- (void)toolBarDidTapSettings:(KBToolBar *)toolBar { + // 这里示例仅插入一个标记。 +// [self.textDocumentProxy insertText:@"[settings]"]; +} + +#pragma mark - KBKeyboardViewDelegate + +- (void)keyboardView:(KBKeyboardView *)keyboard didTapKey:(KBKey *)key { + switch (key.type) { + case KBKeyTypeCharacter: + // 文本插入交由上层控制器处理 + if ([self.delegate respondsToSelector:@selector(keyBoardMainView:didTapKey:)]) { + [self.delegate keyBoardMainView:self didTapKey:key]; + } + break; + case KBKeyTypeBackspace: + if ([self.delegate respondsToSelector:@selector(keyBoardMainView:didTapKey:)]) { + [self.delegate keyBoardMainView:self didTapKey:key]; + } + break; + case KBKeyTypeSpace: + if ([self.delegate respondsToSelector:@selector(keyBoardMainView:didTapKey:)]) { + [self.delegate keyBoardMainView:self didTapKey:key]; + } + break; + case KBKeyTypeReturn: + if ([self.delegate respondsToSelector:@selector(keyBoardMainView:didTapKey:)]) { + [self.delegate keyBoardMainView:self didTapKey:key]; + } + break; + case KBKeyTypeModeChange: { + // 切换 字母 <-> 数字 布局 + keyboard.layoutStyle = (keyboard.layoutStyle == KBKeyboardLayoutStyleLetters) ? KBKeyboardLayoutStyleNumbers : KBKeyboardLayoutStyleLetters; + [keyboard reloadKeys]; + } break; + case KBKeyTypeGlobe: + if ([self.delegate respondsToSelector:@selector(keyBoardMainView:didTapKey:)]) { + [self.delegate keyBoardMainView:self didTapKey:key]; + } + break; + case KBKeyTypeCustom: + // 自定义占位:切换语言或其它操作 + if ([self.delegate respondsToSelector:@selector(keyBoardMainView:didTapKey:)]) { + [self.delegate keyBoardMainView:self didTapKey:key]; + } + break; + case KBKeyTypeShift: + // Shift 已在 KBKeyboardView 内部处理 + break; + } +} + +// 切换功能面板交由外部控制器处理(此处不再实现) + +@end diff --git a/keyBoard.xcodeproj/project.pbxproj b/keyBoard.xcodeproj/project.pbxproj index 7833142..ebc56f4 100644 --- a/keyBoard.xcodeproj/project.pbxproj +++ b/keyBoard.xcodeproj/project.pbxproj @@ -35,8 +35,9 @@ 04FC95702EB09516007BD342 /* KBFunctionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC956F2EB09516007BD342 /* KBFunctionView.m */; }; 04FC95732EB09570007BD342 /* KBFunctionBarView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95722EB09570007BD342 /* KBFunctionBarView.m */; }; 04FC95762EB095DE007BD342 /* KBFunctionPasteView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95752EB095DE007BD342 /* KBFunctionPasteView.m */; }; - A1B2C3D42EB0A0A100000001 /* KBFunctionTagCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D32EB0A0A100000001 /* KBFunctionTagCell.m */; }; + 04FC95792EB09BC8007BD342 /* KBKeyBoardMainView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95782EB09BC8007BD342 /* KBKeyBoardMainView.m */; }; 7A36414DFDA5BEC9B7D2E318 /* Pods_CustomKeyboard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C1092FB2B452F95B15D4263 /* Pods_CustomKeyboard.framework */; }; + A1B2C3D42EB0A0A100000001 /* KBFunctionTagCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D32EB0A0A100000001 /* KBFunctionTagCell.m */; }; ECC9EE02174D86E8D792472F /* Pods_keyBoard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 967065BB5230E43F293B3AF9 /* Pods_keyBoard.framework */; }; /* End PBXBuildFile section */ @@ -123,12 +124,14 @@ 04FC95722EB09570007BD342 /* KBFunctionBarView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFunctionBarView.m; sourceTree = ""; }; 04FC95742EB095DE007BD342 /* KBFunctionPasteView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFunctionPasteView.h; sourceTree = ""; }; 04FC95752EB095DE007BD342 /* KBFunctionPasteView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFunctionPasteView.m; sourceTree = ""; }; - A1B2C3D22EB0A0A100000001 /* KBFunctionTagCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFunctionTagCell.h; sourceTree = ""; }; - A1B2C3D32EB0A0A100000001 /* KBFunctionTagCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFunctionTagCell.m; sourceTree = ""; }; + 04FC95772EB09BC8007BD342 /* KBKeyBoardMainView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBKeyBoardMainView.h; sourceTree = ""; }; + 04FC95782EB09BC8007BD342 /* KBKeyBoardMainView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBKeyBoardMainView.m; sourceTree = ""; }; 2C1092FB2B452F95B15D4263 /* Pods_CustomKeyboard.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CustomKeyboard.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 51FE7C4C42C2255B3C1C4128 /* Pods-keyBoard.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-keyBoard.release.xcconfig"; path = "Target Support Files/Pods-keyBoard/Pods-keyBoard.release.xcconfig"; sourceTree = ""; }; 727EC7532EAF848B00B36487 /* keyBoard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = keyBoard.app; sourceTree = BUILT_PRODUCTS_DIR; }; 967065BB5230E43F293B3AF9 /* Pods_keyBoard.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_keyBoard.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + A1B2C3D22EB0A0A100000001 /* KBFunctionTagCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFunctionTagCell.h; sourceTree = ""; }; + A1B2C3D32EB0A0A100000001 /* KBFunctionTagCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFunctionTagCell.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 = ""; }; @@ -193,6 +196,8 @@ 04C6EADC2EAF8CEB0089C901 /* KBToolBar.m */, 04FC95682EB05497007BD342 /* KBKeyButton.h */, 04FC95692EB05497007BD342 /* KBKeyButton.m */, + 04FC95772EB09BC8007BD342 /* KBKeyBoardMainView.h */, + 04FC95782EB09BC8007BD342 /* KBKeyBoardMainView.m */, 04FC956B2EB054B7007BD342 /* KBKeyboardView.h */, 04FC956C2EB054B7007BD342 /* KBKeyboardView.m */, 04FC956E2EB09516007BD342 /* KBFunctionView.h */, @@ -483,6 +488,7 @@ buildActionMask = 2147483647; files = ( 04C6EADD2EAF8CEB0089C901 /* KBToolBar.m in Sources */, + 04FC95792EB09BC8007BD342 /* KBKeyBoardMainView.m in Sources */, 04FC95732EB09570007BD342 /* KBFunctionBarView.m in Sources */, 04C6EAD82EAF870B0089C901 /* KeyboardViewController.m in Sources */, 04FC95762EB095DE007BD342 /* KBFunctionPasteView.m in Sources */,