From fd7b3a7f7570c6c265459691d512b4e7025559a6 Mon Sep 17 00:00:00 2001 From: CodeST <694468528@qq.com> Date: Fri, 21 Nov 2025 19:40:57 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=94=AE=E7=9B=98=E5=BC=B9?= =?UTF-8?q?=E5=87=BA=E5=AE=BD=E5=BA=A6=20=E4=BC=98=E5=8C=96=E9=94=AE?= =?UTF-8?q?=E7=9B=98=E6=8C=89=E9=92=AE=E8=A7=86=E8=A7=89=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CustomKeyboard/View/KBKeyButton.m | 78 +++++++++++++++++++++++++--- CustomKeyboard/View/KBKeyboardView.m | 3 +- 2 files changed, 73 insertions(+), 8 deletions(-) diff --git a/CustomKeyboard/View/KBKeyButton.m b/CustomKeyboard/View/KBKeyButton.m index 01e9b47..8024b36 100644 --- a/CustomKeyboard/View/KBKeyButton.m +++ b/CustomKeyboard/View/KBKeyButton.m @@ -10,12 +10,23 @@ @interface KBKeyButton () // 内部缓存:便于从按钮查找到所属的 KBKeyboardView @property (nonatomic, weak, readonly) UIView *kb_keyboardContainer; +@property (nonatomic, strong) UIImageView *normalImageView; /// 没有皮肤的时候展示 +@property (nonatomic, strong) UIColor *baseBackgroundColor; /// 无按下状态下,由皮肤/主题决定的底色(由 normalImageView 展示) + @end @implementation KBKeyButton - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { + [self addSubview:self.normalImageView]; + self.normalImageView.translatesAutoresizingMaskIntoConstraints = NO; + [NSLayoutConstraint activateConstraints:@[ + [self.normalImageView.topAnchor constraintEqualToAnchor:self.topAnchor], + [self.normalImageView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor], + [self.normalImageView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:2], + [self.normalImageView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-2], + ]]; [self applyDefaultStyle]; } return self; @@ -26,13 +37,16 @@ KBSkinTheme *t = [KBSkinManager shared].current; [self setTitleColor:t.keyTextColor forState:UIControlStateNormal]; [self setTitleColor:t.keyTextColor forState:UIControlStateHighlighted]; - self.backgroundColor = t.keyBackground; + // 颜色由 normalImageView 控制,按钮本身保持透明,避免叠加背景影响视觉 + self.backgroundColor = [UIColor clearColor]; self.layer.cornerRadius = 6.0; // 圆角 self.layer.masksToBounds = NO; self.layer.shadowColor = [UIColor colorWithWhite:0 alpha:0.1].CGColor; // 阴影效果 self.layer.shadowOpacity = 1.0; self.layer.shadowOffset = CGSizeMake(0, 1); self.layer.shadowRadius = 1.5; + + // 初始状态下根据主题设置底色(给没有皮肤图的按键使用) [self refreshStateAppearance]; // 懒创建图标视图,用于后续皮肤按键小图标展示 @@ -67,10 +81,19 @@ // 按下时整体做一个等比缩放动画,不改背景色和透明度。 // 这样无论是纯文字键还是整块皮肤图,都有统一的“按下”视觉反馈。 CGFloat scale = highlighted ? 0.9 : 1.0; // 可根据手感微调 0.9~0.95 + + // 没有皮肤图片时,normalImageView 做灰度按下效果 + BOOL hasIcon = (self.iconView.image != nil); + UIColor *normalBgColor = self.baseBackgroundColor ?: [UIColor whiteColor]; + UIColor *highlightBgColor = [self kb_darkerColorForColor:normalBgColor]; + [UIView animateWithDuration:0.08 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseOut animations:^{ + if (!hasIcon && !self.normalImageView.hidden) { + self.normalImageView.backgroundColor = highlighted ? highlightBgColor : normalBgColor; + } self.transform = CGAffineTransformMakeScale(scale, scale); } completion:nil]; @@ -101,11 +124,26 @@ - (void)refreshStateAppearance { // 选中态用于 Shift/CapsLock 等特殊按键的高亮显示 KBSkinTheme *t = [KBSkinManager shared].current; + UIColor *base = nil; if (self.isSelected) { - self.backgroundColor = t.keyHighlightBackground ?: t.keyBackground; + base = t.keyHighlightBackground ?: t.keyBackground; } else { - self.backgroundColor = t.keyBackground; + base = t.keyBackground; } + if (!base) { + base = [UIColor whiteColor]; + } + + self.baseBackgroundColor = base; + // 按键背景统一由 normalImageView 控制,按钮本身透明 + self.backgroundColor = [UIColor clearColor]; + + // 有皮肤图时仅展示 icon,不再显示普通背景色 + if (self.iconView.image != nil || self.normalImageView.hidden) { + return; + } + + self.normalImageView.backgroundColor = base; } - (void)applyThemeForCurrentKey { @@ -121,16 +159,14 @@ self.iconView.hidden = (iconImg == nil); BOOL hasIcon = (iconImg != nil); - + self.normalImageView.hidden = hasIcon; if (hasIcon) { // 有图标:仅显示图片,完全隐藏文字 [self setTitle:@"" forState:UIControlStateNormal]; [self setTitle:@"" forState:UIControlStateHighlighted]; [self setTitle:@"" forState:UIControlStateSelected]; self.titleLabel.hidden = YES; - KBSkinTheme *t = [KBSkinManager shared].current; - t.keyBackground = [UIColor clearColor]; - + self.normalImageView.backgroundColor = [UIColor clearColor]; } else { // 无图标:按键标题正常显示(使用 key.title),并根据 hidden_keys 决定要不要隐藏 [self setTitle:self.key.title forState:UIControlStateNormal]; @@ -139,6 +175,34 @@ } } +- (UIImageView *)normalImageView{ + if (!_normalImageView) { + _normalImageView = [[UIImageView alloc] init]; + // 初始给一个默认色,后续会由 refreshStateAppearance / 皮肤统一覆盖 + _normalImageView.backgroundColor = [UIColor whiteColor]; + _normalImageView.layer.cornerRadius = 6; + _normalImageView.layer.masksToBounds = true; + } + return _normalImageView; +} + +/// 在当前底色的基础上略微变暗,作为按下时的“灰度”效果 +- (UIColor *)kb_darkerColorForColor:(UIColor *)color { + if (!color) return [UIColor colorWithWhite:0.9 alpha:1.0]; + + CGFloat h = 0, s = 0, b = 0, a = 0; + if ([color getHue:&h saturation:&s brightness:&b alpha:&a]) { + return [UIColor colorWithHue:h saturation:s brightness:MAX(b * 0.9, 0.0) alpha:a]; + } + + CGFloat white = 0; + if ([color getWhite:&white alpha:&a]) { + return [UIColor colorWithWhite:MAX(white * 0.9, 0.0) alpha:a]; + } + + return color; +} + @end @implementation KBKeyButton (KBKeyboardContainer) diff --git a/CustomKeyboard/View/KBKeyboardView.m b/CustomKeyboard/View/KBKeyboardView.m index 9582425..e46b622 100644 --- a/CustomKeyboard/View/KBKeyboardView.m +++ b/CustomKeyboard/View/KBKeyboardView.m @@ -620,7 +620,8 @@ edgeSpacerMultiplier:(CGFloat)edgeSpacerMultiplier { // 计算预览视图位置:在按钮上方稍微偏上 CGRect btnFrameInSelf = [button convertRect:button.bounds toView:self]; - CGFloat previewWidth = MAX(CGRectGetWidth(btnFrameInSelf) * 1.4, 42.0); +// CGFloat previewWidth = MAX(CGRectGetWidth(btnFrameInSelf) * 1.4, 42.0); + CGFloat previewWidth = 42; CGFloat previewHeight = CGRectGetHeight(btnFrameInSelf) * 1.2; CGFloat centerX = CGRectGetMidX(btnFrameInSelf); CGFloat centerY = CGRectGetMinY(btnFrameInSelf) - previewHeight * 0.6;