diff --git a/CustomKeyboard/KeyboardViewController.m b/CustomKeyboard/KeyboardViewController.m index 20b6069..742350d 100644 --- a/CustomKeyboard/KeyboardViewController.m +++ b/CustomKeyboard/KeyboardViewController.m @@ -47,6 +47,7 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center, @interface KeyboardViewController () @property (nonatomic, strong) UIButton *nextKeyboardButton; // 系统“下一个键盘”按钮(可选) +@property (nonatomic, strong) UIView *contentView; @property (nonatomic, strong) KBKeyBoardMainView *keyBoardMainView; // 功能面板视图(点击工具栏第0个时显示) @property (nonatomic, strong) KBFunctionView *functionView; // 功能面板视图(点击工具栏第0个时显示) @property (nonatomic, strong) KBSettingView *settingView; // 设置页 @@ -55,6 +56,12 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center, @property (nonatomic, strong) KBSuggestionEngine *suggestionEngine; @property (nonatomic, copy) NSString *currentWord; @property (nonatomic, assign) BOOL suppressSuggestions; +@property (nonatomic, strong) MASConstraint *contentWidthConstraint; +@property (nonatomic, strong) MASConstraint *contentHeightConstraint; +@property (nonatomic, strong) NSLayoutConstraint *kb_heightConstraint; +@property (nonatomic, strong) NSLayoutConstraint *kb_widthConstraint; +@property (nonatomic, assign) CGFloat kb_lastPortraitWidth; +@property (nonatomic, assign) CGFloat kb_lastKeyboardHeight; @end @implementation KeyboardViewController @@ -119,13 +126,16 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center, - (void)setupUI { self.view.translatesAutoresizingMaskIntoConstraints = NO; - // 按屏幕宽度对设计值做等比缩放,避免在不同机型上键盘整体高度失真导致皮肤被压缩/拉伸 - CGFloat keyboardHeight = KBFit(kKBKeyboardBaseHeight); - CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width; + // 按“短边”宽度等比缩放,横屏保持竖屏布局比例 + CGFloat portraitWidth = [self kb_portraitWidth]; + CGFloat keyboardHeight = [self kb_keyboardHeightForWidth:portraitWidth]; + CGFloat screenWidth = CGRectGetWidth([UIScreen mainScreen].bounds); CGFloat outerVerticalInset = KBFit(4.0f); NSLayoutConstraint *h = [self.view.heightAnchor constraintEqualToConstant:keyboardHeight]; NSLayoutConstraint *w = [self.view.widthAnchor constraintEqualToConstant:screenWidth]; + self.kb_heightConstraint = h; + self.kb_widthConstraint = w; h.priority = UILayoutPriorityRequired; w.priority = UILayoutPriorityRequired; @@ -137,25 +147,30 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center, iv.allowsSelfSizing = NO; } } - // 背景图铺底 - [self.view addSubview:self.bgImageView]; + // 内容容器:横屏时保持竖屏宽度,居中显示 + [self.view addSubview:self.contentView]; + [self.contentView mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerX.equalTo(self.view); + make.bottom.equalTo(self.view); + self.contentWidthConstraint = make.width.mas_equalTo(portraitWidth); + self.contentHeightConstraint = make.height.mas_equalTo(keyboardHeight); + }]; + + // 背景图铺底(仅在内容容器内) + [self.contentView addSubview:self.bgImageView]; [self.bgImageView mas_makeConstraints:^(MASConstraintMaker *make) { - make.edges.equalTo(self.view); + make.edges.equalTo(self.contentView); }]; // 预置功能面板(默认隐藏),与键盘区域共享相同布局 self.functionView.hidden = YES; - [self.view addSubview:self.functionView]; + [self.contentView addSubview:self.functionView]; [self.functionView mas_makeConstraints:^(MASConstraintMaker *make) { - make.left.right.equalTo(self.view); - make.top.equalTo(self.view).offset(0); - make.bottom.equalTo(self.view).offset(0); + make.edges.equalTo(self.contentView); }]; - [self.view addSubview:self.keyBoardMainView]; + [self.contentView addSubview:self.keyBoardMainView]; [self.keyBoardMainView mas_makeConstraints:^(MASConstraintMaker *make) { - make.left.right.equalTo(self.view); - make.top.equalTo(self.view).offset(0); - make.bottom.equalTo(self.view.mas_bottom).offset(-0); + make.edges.equalTo(self.contentView); }]; } @@ -291,9 +306,9 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center, // 可选:把当前显示的视图置顶,避免层级遮挡 if (show) { - [self.view bringSubviewToFront:self.functionView]; + [self.contentView bringSubviewToFront:self.functionView]; } else { - [self.view bringSubviewToFront:self.keyBoardMainView]; + [self.contentView bringSubviewToFront:self.keyBoardMainView]; } } @@ -307,19 +322,19 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center, // if (!self.settingView) { self.settingView = [[KBSettingView alloc] init]; self.settingView.hidden = YES; - [self.view addSubview:self.settingView]; + [self.contentView addSubview:self.settingView]; [self.settingView mas_makeConstraints:^(MASConstraintMaker *make) { // 与键盘主视图完全等同的区域,保证高度、宽度一致 - make.edges.equalTo(self.keyBoardMainView); + make.edges.equalTo(self.contentView); }]; [self.settingView.backButton addTarget:self action:@selector(onTapSettingsBack) forControlEvents:UIControlEventTouchUpInside]; // } - [self.view bringSubviewToFront:self.settingView]; + [self.contentView bringSubviewToFront:self.settingView]; // 以 keyBoardMainView 的实际宽度为准,避免首次添加时 self.view 宽度尚未计算 - [self.view layoutIfNeeded]; + [self.contentView layoutIfNeeded]; CGFloat w = CGRectGetWidth(self.keyBoardMainView.bounds); - if (w <= 0) { w = CGRectGetWidth(self.view.bounds); } - if (w <= 0) { w = [UIScreen mainScreen].bounds.size.width; } + if (w <= 0) { w = CGRectGetWidth(self.contentView.bounds); } + if (w <= 0) { w = [self kb_portraitWidth]; } self.settingView.transform = CGAffineTransformMakeTranslation(w, 0); self.settingView.hidden = NO; [UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ @@ -328,8 +343,8 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center, } else { if (!self.settingView || self.settingView.hidden) return; CGFloat w = CGRectGetWidth(self.keyBoardMainView.bounds); - if (w <= 0) { w = CGRectGetWidth(self.view.bounds); } - if (w <= 0) { w = [UIScreen mainScreen].bounds.size.width; } + if (w <= 0) { w = CGRectGetWidth(self.contentView.bounds); } + if (w <= 0) { w = [self kb_portraitWidth]; } [UIView animateWithDuration:0.22 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ self.settingView.transform = CGAffineTransformMakeTranslation(w, 0); } completion:^(BOOL finished) { @@ -363,15 +378,15 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center, KBKeyboardSubscriptionView *panel = self.subscriptionView; if (!panel.superview) { panel.hidden = YES; - [self.view addSubview:panel]; + [self.contentView addSubview:panel]; [panel mas_makeConstraints:^(MASConstraintMaker *make) { - make.edges.equalTo(self.keyBoardMainView); + make.edges.equalTo(self.contentView); }]; } - [self.view bringSubviewToFront:panel]; + [self.contentView bringSubviewToFront:panel]; panel.hidden = NO; panel.alpha = 0.0; - CGFloat height = CGRectGetHeight(self.view.bounds); + CGFloat height = CGRectGetHeight(self.contentView.bounds); if (height <= 0) { height = 260; } panel.transform = CGAffineTransformMakeTranslation(0, height); [panel refreshProductsIfNeeded]; @@ -384,7 +399,7 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center, - (void)hideSubscriptionPanel { if (!self.subscriptionView || self.subscriptionView.hidden) { return; } CGFloat height = CGRectGetHeight(self.subscriptionView.bounds); - if (height <= 0) { height = CGRectGetHeight(self.view.bounds); } + if (height <= 0) { height = CGRectGetHeight(self.contentView.bounds); } KBKeyboardSubscriptionView *panel = self.subscriptionView; [UIView animateWithDuration:0.22 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ panel.alpha = 0.0; @@ -679,6 +694,21 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center, // } } +- (void)viewDidLayoutSubviews { + [super viewDidLayoutSubviews]; + [self kb_updateKeyboardLayoutIfNeeded]; +} + +- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { + [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; + __weak typeof(self) weakSelf = self; + [coordinator animateAlongsideTransition:^(id _Nonnull context) { + [weakSelf kb_updateKeyboardLayoutIfNeeded]; + } completion:^(__unused id _Nonnull context) { + [weakSelf kb_updateKeyboardLayoutIfNeeded]; + }]; +} + //- (void)kb_tryOpenContainerForLoginIfNeeded { // // 使用与主 App 一致的自定义 Scheme // NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@@//login?src=keyboard", KB_APP_SCHEME]]; @@ -699,6 +729,7 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center, self.bgImageView.image = img; BOOL hasImg = (img != nil); self.view.backgroundColor = hasImg ? [UIColor clearColor] : t.keyboardBackground; + self.contentView.backgroundColor = hasImg ? [UIColor clearColor] : t.keyboardBackground; self.keyBoardMainView.backgroundColor = hasImg ? [UIColor clearColor] : t.keyboardBackground; // 触发键区按主题重绘 if ([self.keyBoardMainView respondsToSelector:@selector(kb_applyTheme)]) { @@ -732,8 +763,62 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center, }]; } +#pragma mark - Layout Helpers + +- (CGFloat)kb_portraitWidth { + CGSize s = [UIScreen mainScreen].bounds.size; + return MIN(s.width, s.height); +} + +- (CGFloat)kb_keyboardHeightForWidth:(CGFloat)width { + if (width <= 0) { width = KB_DESIGN_WIDTH; } + return kKBKeyboardBaseHeight * (width / KB_DESIGN_WIDTH); +} + +- (void)kb_updateKeyboardLayoutIfNeeded { + CGFloat portraitWidth = [self kb_portraitWidth]; + CGFloat keyboardHeight = [self kb_keyboardHeightForWidth:portraitWidth]; + CGFloat containerWidth = CGRectGetWidth(self.view.superview.bounds); + if (containerWidth <= 0) { + containerWidth = CGRectGetWidth(self.view.window.bounds); + } + if (containerWidth <= 0) { + containerWidth = CGRectGetWidth([UIScreen mainScreen].bounds); + } + + BOOL widthChanged = (fabs(self.kb_lastPortraitWidth - portraitWidth) >= 0.5); + BOOL heightChanged = (fabs(self.kb_lastKeyboardHeight - keyboardHeight) >= 0.5); + if (!widthChanged && !heightChanged && containerWidth > 0 && self.kb_widthConstraint.constant == containerWidth) { + return; + } + self.kb_lastPortraitWidth = portraitWidth; + self.kb_lastKeyboardHeight = keyboardHeight; + + if (self.kb_heightConstraint) { + self.kb_heightConstraint.constant = keyboardHeight; + } + if (containerWidth > 0 && self.kb_widthConstraint) { + self.kb_widthConstraint.constant = containerWidth; + } + if (self.contentWidthConstraint) { + [self.contentWidthConstraint setOffset:portraitWidth]; + } + if (self.contentHeightConstraint) { + [self.contentHeightConstraint setOffset:keyboardHeight]; + } + [self.view layoutIfNeeded]; +} + #pragma mark - Lazy +- (UIView *)contentView { + if (!_contentView) { + _contentView = [[UIView alloc] init]; + _contentView.backgroundColor = [UIColor clearColor]; + } + return _contentView; +} + - (UIImageView *)bgImageView { if (!_bgImageView) { _bgImageView = [[UIImageView alloc] init]; diff --git a/KBMaiPointEventTable.xlsx b/KBMaiPointEventTable.xlsx index 785e13b..aab2771 100644 Binary files a/KBMaiPointEventTable.xlsx and b/KBMaiPointEventTable.xlsx differ diff --git a/Shared/KBConfig.h b/Shared/KBConfig.h index f4e1869..171cfaa 100644 --- a/Shared/KBConfig.h +++ b/Shared/KBConfig.h @@ -88,7 +88,8 @@ #if __OBJC__ static inline CGFloat KBScreenWidth(void) { - return [UIScreen mainScreen].bounds.size.width; + CGSize size = [UIScreen mainScreen].bounds.size; + return MIN(size.width, size.height); } static inline CGFloat KBScaleFactor(void) {