Files
keyboard/CustomKeyboard/View/KBKeyButton.m
2025-11-20 21:11:27 +08:00

159 lines
5.8 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// KBKeyButton.m
// CustomKeyboard
//
#import "KBKeyButton.h"
#import "KBKey.h"
#import "KBSkinManager.h"
@interface KBKeyButton ()
// 内部缓存:便于从按钮查找到所属的 KBKeyboardView
@property (nonatomic, weak, readonly) UIView *kb_keyboardContainer;
@end
@implementation KBKeyButton
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self applyDefaultStyle];
}
return self;
}
- (void)applyDefaultStyle {
self.titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold];
KBSkinTheme *t = [KBSkinManager shared].current;
[self setTitleColor:t.keyTextColor forState:UIControlStateNormal];
[self setTitleColor:t.keyTextColor forState:UIControlStateHighlighted];
self.backgroundColor = t.keyBackground;
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];
// 懒创建图标视图,用于后续皮肤按键小图标展示
if (!self.iconView) {
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectZero];
// 作为按键的整块皮肤背景,铺满整个按钮区域
iv.contentMode = UIViewContentModeScaleToFill;
iv.clipsToBounds = YES;
iv.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:iv];
// 让皮肤图片撑满整个按钮
[NSLayoutConstraint activateConstraints:@[
[iv.topAnchor constraintEqualToAnchor:self.topAnchor],
[iv.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
[iv.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
[iv.trailingAnchor constraintEqualToAnchor:self.trailingAnchor],
]];
self.iconView = iv;
// 文字保持居中;若需要显示文字,则覆盖在皮肤图片之上
self.titleEdgeInsets = UIEdgeInsetsZero;
[self bringSubviewToFront:self.titleLabel];
}
}
- (void)setKey:(KBKey *)key {
_key = key;
}
- (void)setHighlighted:(BOOL)highlighted {
[super setHighlighted:highlighted];
// 按下时整体做一个等比缩放动画,不改背景色和透明度。
// 这样无论是纯文字键还是整块皮肤图,都有统一的“按下”视觉反馈。
CGFloat scale = highlighted ? 0.9 : 1.0; // 可根据手感微调 0.9~0.95
[UIView animateWithDuration:0.08
delay:0
options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseOut
animations:^{
self.transform = CGAffineTransformMakeScale(scale, scale);
}
completion:nil];
// 将“按下/抬起”事件转发给键盘视图,用于显示/隐藏顶部预览气泡。
UIView *container = self.kb_keyboardContainer;
if ([container respondsToSelector:@selector(showPreviewForButton:)] &&
[container respondsToSelector:@selector(hidePreview)]) {
if (highlighted) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[container performSelector:@selector(showPreviewForButton:) withObject:self];
#pragma clang diagnostic pop
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[container performSelector:@selector(hidePreview)];
#pragma clang diagnostic pop
}
}
}
- (void)setSelected:(BOOL)selected {
[super setSelected:selected];
[self refreshStateAppearance];
}
- (void)refreshStateAppearance {
// 选中态用于 Shift/CapsLock 等特殊按键的高亮显示
KBSkinTheme *t = [KBSkinManager shared].current;
if (self.isSelected) {
self.backgroundColor = t.keyHighlightBackground ?: t.keyBackground;
} else {
self.backgroundColor = t.keyBackground;
}
}
- (void)applyThemeForCurrentKey {
// 根据皮肤映射加载图标(若有),支持大小写变体:
// - identifier: 逻辑按键标识(如 letter_q
// - caseVariant: 0/1/2 => 无变体/小写/大写
NSString *identifier = self.key.identifier;
NSInteger variant = (NSInteger)self.key.caseVariant;
UIImage *iconImg = [[KBSkinManager shared] iconImageForKeyIdentifier:identifier caseVariant:variant];
// 设置整块按键背景图(若有)
self.iconView.image = iconImg;
self.iconView.hidden = (iconImg == nil);
BOOL hasIcon = (iconImg != nil);
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];
} else {
// 无图标:按键标题正常显示(使用 key.title并根据 hidden_keys 决定要不要隐藏
[self setTitle:self.key.title forState:UIControlStateNormal];
BOOL hideTextBySkin = [[KBSkinManager shared] shouldHideKeyTextForIdentifier:identifier];
self.titleLabel.hidden = hideTextBySkin;
}
}
@end
@implementation KBKeyButton (KBKeyboardContainer)
- (UIView *)kb_keyboardContainer {
UIView *v = self.superview;
while (v) {
// KBKeyboardView 是当前容器类型,这里用类名字符串避免直接引用头文件死循环
if ([NSStringFromClass(v.class) isEqualToString:@"KBKeyboardView"]) {
return v;
}
v = v.superview;
}
return nil;
}
@end