1
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#import "KBSkinManager.h"
|
||||
#import "KBKeyPreviewView.h"
|
||||
#import "KBBackspaceLongPressHandler.h"
|
||||
#import "KBKeyboardLayoutConfig.h"
|
||||
|
||||
// UI 常量统一管理,方便后续调试样式(以 375 宽设计稿为基准,通过 KBFit 做等比缩放)
|
||||
#define kKBRowVerticalSpacing KBFit(8.0f)
|
||||
@@ -33,6 +34,7 @@ static const CGFloat kKBLettersRow2EdgeSpacerMultiplier = 0.5;
|
||||
@property (nonatomic, strong) NSArray<NSArray<KBKey *> *> *keysForRows;
|
||||
@property (nonatomic, strong) KBBackspaceLongPressHandler *backspaceHandler;
|
||||
@property (nonatomic, strong) KBKeyPreviewView *previewView;
|
||||
@property (nonatomic, strong) KBKeyboardLayoutConfig *layoutConfig;
|
||||
@end
|
||||
|
||||
@implementation KBKeyboardView
|
||||
@@ -44,6 +46,7 @@ static const CGFloat kKBLettersRow2EdgeSpacerMultiplier = 0.5;
|
||||
// 默认小写:与需求一致,初始不开启 Shift
|
||||
_shiftOn = NO;
|
||||
_symbolsMoreOn = NO; // 数字面板默认第一页(123)
|
||||
self.layoutConfig = [KBKeyboardLayoutConfig sharedConfig];
|
||||
self.backspaceHandler = [[KBBackspaceLongPressHandler alloc] initWithContainerView:self];
|
||||
[self buildBase];
|
||||
[self reloadKeys];
|
||||
@@ -67,26 +70,39 @@ static const CGFloat kKBLettersRow2EdgeSpacerMultiplier = 0.5;
|
||||
[self addSubview:self.row3];
|
||||
[self addSubview:self.row4];
|
||||
|
||||
KBKeyboardLayoutConfig *config = [self kb_layoutConfig];
|
||||
KBKeyboardLayout *layout = [self kb_layoutForName:@"letters"];
|
||||
NSArray<KBKeyboardRowConfig *> *rows = layout.rows ?: @[];
|
||||
|
||||
CGFloat rowSpacing = [self kb_metricValue:config.metrics.rowSpacing fallback:nil defaultValue:8.0];
|
||||
CGFloat topInset = [self kb_metricValue:config.metrics.topInset fallback:nil defaultValue:8.0];
|
||||
CGFloat bottomInset = [self kb_metricValue:config.metrics.bottomInset fallback:nil defaultValue:6.0];
|
||||
|
||||
CGFloat row1Height = [self kb_rowHeightForRow:(rows.count > 0 ? rows[0] : nil)];
|
||||
CGFloat row2Height = [self kb_rowHeightForRow:(rows.count > 1 ? rows[1] : nil)];
|
||||
CGFloat row3Height = [self kb_rowHeightForRow:(rows.count > 2 ? rows[2] : nil)];
|
||||
CGFloat row4Height = [self kb_rowHeightForRow:(rows.count > 3 ? rows[3] : nil)];
|
||||
|
||||
[self.row1 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.mas_top).offset(kKBRowVerticalSpacing);
|
||||
make.top.equalTo(self.mas_top).offset(topInset);
|
||||
make.left.right.equalTo(self);
|
||||
make.height.mas_equalTo(kKBRowHeight);
|
||||
make.height.mas_equalTo(row1Height);
|
||||
}];
|
||||
[self.row2 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.row1.mas_bottom).offset(kKBRowVerticalSpacing);
|
||||
make.top.equalTo(self.row1.mas_bottom).offset(rowSpacing);
|
||||
make.left.right.equalTo(self);
|
||||
make.height.equalTo(self.row1);
|
||||
make.height.mas_equalTo(row2Height);
|
||||
}];
|
||||
[self.row3 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.row2.mas_bottom).offset(kKBRowVerticalSpacing);
|
||||
make.top.equalTo(self.row2.mas_bottom).offset(rowSpacing);
|
||||
make.left.right.equalTo(self);
|
||||
make.height.equalTo(self.row1);
|
||||
make.height.mas_equalTo(row3Height);
|
||||
}];
|
||||
[self.row4 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.row3.mas_bottom).offset(kKBRowVerticalSpacing);
|
||||
make.top.equalTo(self.row3.mas_bottom).offset(rowSpacing);
|
||||
make.left.right.equalTo(self);
|
||||
make.height.equalTo(self.row1);
|
||||
make.bottom.equalTo(self.mas_bottom).offset(-6);
|
||||
make.height.mas_equalTo(row4Height);
|
||||
make.bottom.equalTo(self.mas_bottom).offset(-bottomInset);
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -99,18 +115,17 @@ static const CGFloat kKBLettersRow2EdgeSpacerMultiplier = 0.5;
|
||||
[row.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
}
|
||||
|
||||
self.keysForRows = [self buildKeysForCurrentLayout];
|
||||
if (self.keysForRows.count < 4) return;
|
||||
KBKeyboardLayout *layout = [self kb_currentLayout];
|
||||
NSArray<KBKeyboardRowConfig *> *rows = layout.rows ?: @[];
|
||||
if (rows.count < 4) {
|
||||
[self kb_buildLegacyLayout];
|
||||
return;
|
||||
}
|
||||
|
||||
[self buildRow:self.row1 withKeys:self.keysForRows[0]];
|
||||
|
||||
// 第二行:字母布局时通过左右等宽占位让整行居中
|
||||
CGFloat row2Spacer = (self.layoutStyle == KBKeyboardLayoutStyleLetters)
|
||||
? kKBLettersRow2EdgeSpacerMultiplier : 0.0;
|
||||
[self buildRow:self.row2 withKeys:self.keysForRows[1] edgeSpacerMultiplier:row2Spacer];
|
||||
|
||||
[self buildRow:self.row3 withKeys:self.keysForRows[2]];
|
||||
[self buildRow:self.row4 withKeys:self.keysForRows[3]];
|
||||
[self buildRow:self.row1 withRowConfig:rows[0]];
|
||||
[self buildRow:self.row2 withRowConfig:rows[1]];
|
||||
[self buildRow:self.row3 withRowConfig:rows[2]];
|
||||
[self buildRow:self.row4 withRowConfig:rows[3]];
|
||||
}
|
||||
|
||||
#pragma mark - Key Model Construction
|
||||
@@ -315,6 +330,152 @@ static const CGFloat kKBLettersRow2EdgeSpacerMultiplier = 0.5;
|
||||
|
||||
#pragma mark - Row Building
|
||||
|
||||
- (void)buildRow:(UIView *)row withRowConfig:(KBKeyboardRowConfig *)rowConfig {
|
||||
if (!row || !rowConfig) { return; }
|
||||
CGFloat gap = [self kb_gapForRow:rowConfig];
|
||||
CGFloat insetLeft = [self kb_insetLeftForRow:rowConfig];
|
||||
CGFloat insetRight = [self kb_insetRightForRow:rowConfig];
|
||||
|
||||
if (rowConfig.segments) {
|
||||
KBKeyboardRowSegments *segments = rowConfig.segments;
|
||||
NSArray<KBKeyboardRowItem *> *leftItems = [segments leftItems];
|
||||
NSArray<KBKeyboardRowItem *> *centerItems = [segments centerItems];
|
||||
NSArray<KBKeyboardRowItem *> *rightItems = [segments rightItems];
|
||||
UIView *leftContainer = [UIView new];
|
||||
UIView *centerContainer = [UIView new];
|
||||
UIView *rightContainer = [UIView new];
|
||||
[row addSubview:leftContainer];
|
||||
[row addSubview:centerContainer];
|
||||
[row addSubview:rightContainer];
|
||||
|
||||
[leftContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(row.mas_left).offset(insetLeft);
|
||||
make.top.bottom.equalTo(row);
|
||||
}];
|
||||
[rightContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(row.mas_right).offset(-insetRight);
|
||||
make.top.bottom.equalTo(row);
|
||||
}];
|
||||
[centerContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.equalTo(row);
|
||||
make.top.bottom.equalTo(row);
|
||||
make.left.greaterThanOrEqualTo(leftContainer.mas_right).offset(gap);
|
||||
make.right.lessThanOrEqualTo(rightContainer.mas_left).offset(-gap);
|
||||
}];
|
||||
|
||||
if (leftItems.count == 0) {
|
||||
[leftContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(0);
|
||||
}];
|
||||
}
|
||||
if (centerItems.count == 0) {
|
||||
[centerContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(0);
|
||||
}];
|
||||
}
|
||||
if (rightItems.count == 0) {
|
||||
[rightContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(0);
|
||||
}];
|
||||
}
|
||||
|
||||
[self kb_buildButtonsInContainer:leftContainer
|
||||
items:leftItems
|
||||
gap:gap
|
||||
insetLeft:0
|
||||
insetRight:0
|
||||
alignCenter:NO];
|
||||
[self kb_buildButtonsInContainer:centerContainer
|
||||
items:centerItems
|
||||
gap:gap
|
||||
insetLeft:0
|
||||
insetRight:0
|
||||
alignCenter:NO];
|
||||
[self kb_buildButtonsInContainer:rightContainer
|
||||
items:rightItems
|
||||
gap:gap
|
||||
insetLeft:0
|
||||
insetRight:0
|
||||
alignCenter:NO];
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL alignCenter = [rowConfig.align.lowercaseString isEqualToString:@"center"];
|
||||
[self kb_buildButtonsInContainer:row
|
||||
items:[rowConfig resolvedItems]
|
||||
gap:gap
|
||||
insetLeft:insetLeft
|
||||
insetRight:insetRight
|
||||
alignCenter:alignCenter];
|
||||
}
|
||||
|
||||
- (void)kb_buildButtonsInContainer:(UIView *)container
|
||||
items:(NSArray<KBKeyboardRowItem *> *)items
|
||||
gap:(CGFloat)gap
|
||||
insetLeft:(CGFloat)insetLeft
|
||||
insetRight:(CGFloat)insetRight
|
||||
alignCenter:(BOOL)alignCenter {
|
||||
if (items.count == 0) { return; }
|
||||
|
||||
UIView *leftSpacer = nil;
|
||||
UIView *rightSpacer = nil;
|
||||
if (alignCenter) {
|
||||
leftSpacer = [UIView new];
|
||||
rightSpacer = [UIView new];
|
||||
[container addSubview:leftSpacer];
|
||||
[container addSubview:rightSpacer];
|
||||
[leftSpacer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(container.mas_left).offset(insetLeft);
|
||||
make.top.bottom.equalTo(container);
|
||||
}];
|
||||
[rightSpacer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(container.mas_right).offset(-insetRight);
|
||||
make.top.bottom.equalTo(container);
|
||||
}];
|
||||
[leftSpacer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.equalTo(rightSpacer);
|
||||
}];
|
||||
}
|
||||
|
||||
KBKeyButton *previous = nil;
|
||||
for (KBKeyboardRowItem *item in items) {
|
||||
KBKeyButton *btn = [self kb_buttonForItem:item];
|
||||
if (!btn) { continue; }
|
||||
[container addSubview:btn];
|
||||
|
||||
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.bottom.equalTo(container);
|
||||
if (previous) {
|
||||
make.left.equalTo(previous.mas_right).offset(gap);
|
||||
} else {
|
||||
if (leftSpacer) {
|
||||
make.left.equalTo(leftSpacer.mas_right).offset(gap);
|
||||
} else {
|
||||
make.left.equalTo(container.mas_left).offset(insetLeft);
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
CGFloat width = [self kb_widthForItem:item key:btn.key];
|
||||
if (width > 0.0) {
|
||||
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(width);
|
||||
}];
|
||||
}
|
||||
|
||||
previous = btn;
|
||||
}
|
||||
|
||||
if (!previous) { return; }
|
||||
[previous mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
if (rightSpacer) {
|
||||
make.right.equalTo(rightSpacer.mas_left).offset(-gap);
|
||||
} else {
|
||||
make.right.equalTo(container.mas_right).offset(-insetRight);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)buildRow:(UIView *)row withKeys:(NSArray<KBKey *> *)keys {
|
||||
[self buildRow:row withKeys:keys edgeSpacerMultiplier:0.0];
|
||||
}
|
||||
@@ -581,6 +742,382 @@ edgeSpacerMultiplier:(CGFloat)edgeSpacerMultiplier {
|
||||
// Space 不设置宽度;通过此前已建立的左右约束自动占满剩余宽度。
|
||||
}
|
||||
|
||||
#pragma mark - Config Helpers
|
||||
|
||||
- (KBKeyboardLayoutConfig *)kb_layoutConfig {
|
||||
if (!self.layoutConfig) {
|
||||
self.layoutConfig = [KBKeyboardLayoutConfig sharedConfig];
|
||||
}
|
||||
return self.layoutConfig;
|
||||
}
|
||||
|
||||
- (KBKeyboardLayout *)kb_layoutForName:(NSString *)name {
|
||||
return [[self kb_layoutConfig] layoutForName:name];
|
||||
}
|
||||
|
||||
- (KBKeyboardLayout *)kb_currentLayout {
|
||||
if (self.layoutStyle == KBKeyboardLayoutStyleNumbers) {
|
||||
return [self kb_layoutForName:(self.symbolsMoreOn ? @"symbolsMore" : @"numbers")];
|
||||
}
|
||||
return [self kb_layoutForName:@"letters"];
|
||||
}
|
||||
|
||||
- (void)kb_buildLegacyLayout {
|
||||
self.keysForRows = [self buildKeysForCurrentLayout];
|
||||
if (self.keysForRows.count < 4) { return; }
|
||||
|
||||
[self buildRow:self.row1 withKeys:self.keysForRows[0]];
|
||||
|
||||
CGFloat row2Spacer = (self.layoutStyle == KBKeyboardLayoutStyleLetters)
|
||||
? kKBLettersRow2EdgeSpacerMultiplier : 0.0;
|
||||
[self buildRow:self.row2 withKeys:self.keysForRows[1] edgeSpacerMultiplier:row2Spacer];
|
||||
|
||||
[self buildRow:self.row3 withKeys:self.keysForRows[2]];
|
||||
[self buildRow:self.row4 withKeys:self.keysForRows[3]];
|
||||
}
|
||||
|
||||
- (CGFloat)kb_scaledValue:(CGFloat)designValue {
|
||||
KBKeyboardLayoutConfig *config = [self kb_layoutConfig];
|
||||
if (config) {
|
||||
return [config scaledValue:designValue];
|
||||
}
|
||||
return KBFit(designValue);
|
||||
}
|
||||
|
||||
- (CGFloat)kb_numberValue:(NSNumber *)value defaultValue:(CGFloat)defaultValue {
|
||||
if ([value isKindOfClass:[NSNumber class]]) {
|
||||
return value.doubleValue;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
- (CGFloat)kb_metricValue:(NSNumber *)value fallback:(NSNumber *)fallback defaultValue:(CGFloat)defaultValue {
|
||||
CGFloat v = [self kb_numberValue:value defaultValue:-1.0];
|
||||
if (v < 0.0) {
|
||||
v = [self kb_numberValue:fallback defaultValue:defaultValue];
|
||||
}
|
||||
if (v < 0.0) {
|
||||
v = defaultValue;
|
||||
}
|
||||
return [self kb_scaledValue:v];
|
||||
}
|
||||
|
||||
- (CGFloat)kb_rowHeightForRow:(KBKeyboardRowConfig *)row {
|
||||
KBKeyboardLayoutConfig *config = [self kb_layoutConfig];
|
||||
NSNumber *height = row.height ?: config.metrics.keyHeight;
|
||||
CGFloat value = [self kb_numberValue:height defaultValue:40.0];
|
||||
return [self kb_scaledValue:value];
|
||||
}
|
||||
|
||||
- (CGFloat)kb_gapForRow:(KBKeyboardRowConfig *)row {
|
||||
KBKeyboardLayoutConfig *config = [self kb_layoutConfig];
|
||||
return [self kb_metricValue:row.gap fallback:config.metrics.gap defaultValue:5.0];
|
||||
}
|
||||
|
||||
- (CGFloat)kb_insetLeftForRow:(KBKeyboardRowConfig *)row {
|
||||
KBKeyboardLayoutConfig *config = [self kb_layoutConfig];
|
||||
return [self kb_metricValue:row.insetLeft fallback:config.metrics.edgeInset defaultValue:0.0];
|
||||
}
|
||||
|
||||
- (CGFloat)kb_insetRightForRow:(KBKeyboardRowConfig *)row {
|
||||
KBKeyboardLayoutConfig *config = [self kb_layoutConfig];
|
||||
return [self kb_metricValue:row.insetRight fallback:config.metrics.edgeInset defaultValue:0.0];
|
||||
}
|
||||
|
||||
- (KBKeyButton *)kb_buttonForItem:(KBKeyboardRowItem *)item {
|
||||
if (item.itemId.length == 0) { return nil; }
|
||||
KBKeyboardKeyDef *def = [[self kb_layoutConfig] keyDefForIdentifier:item.itemId];
|
||||
KBKey *key = [self kb_keyForItemId:item.itemId];
|
||||
if (!key) { return nil; }
|
||||
|
||||
KBKeyButton *btn = [[KBKeyButton alloc] init];
|
||||
btn.key = key;
|
||||
[btn setTitle:key.title forState:UIControlStateNormal];
|
||||
|
||||
UIColor *bgColor = [self kb_backgroundColorForItem:item keyDef:def];
|
||||
if (bgColor) {
|
||||
btn.customBackgroundColor = bgColor;
|
||||
}
|
||||
|
||||
CGFloat fontSize = [self kb_fontSizeForItem:item key:key];
|
||||
if (fontSize > 0.0) {
|
||||
btn.titleLabel.font = [UIFont systemFontOfSize:fontSize weight:UIFontWeightSemibold];
|
||||
}
|
||||
|
||||
[btn applyThemeForCurrentKey];
|
||||
[self kb_applySymbolIfNeededForButton:btn keyDef:def fontSize:fontSize];
|
||||
[btn addTarget:self action:@selector(onKeyTapped:) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
if (key.type == KBKeyTypeBackspace) {
|
||||
[self.backspaceHandler bindDeleteButton:btn showClearLabel:YES];
|
||||
}
|
||||
if (key.type == KBKeyTypeShift) {
|
||||
btn.selected = self.shiftOn;
|
||||
}
|
||||
return btn;
|
||||
}
|
||||
|
||||
- (void)kb_applySymbolIfNeededForButton:(KBKeyButton *)button
|
||||
keyDef:(KBKeyboardKeyDef *)def
|
||||
fontSize:(CGFloat)fontSize {
|
||||
if (!button || !def) { return; }
|
||||
if (button.iconView.image != nil) { return; }
|
||||
NSString *symbolName = button.isSelected ? def.selectedSymbolName : def.symbolName;
|
||||
if (symbolName.length == 0) { return; }
|
||||
|
||||
UIImage *image = [UIImage systemImageNamed:symbolName];
|
||||
if (!image) { return; }
|
||||
|
||||
UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:fontSize weight:UIFontWeightSemibold];
|
||||
image = [image imageWithConfiguration:config];
|
||||
|
||||
button.iconView.image = image;
|
||||
button.iconView.hidden = NO;
|
||||
button.iconView.contentMode = UIViewContentModeCenter;
|
||||
button.titleLabel.hidden = YES;
|
||||
|
||||
UIColor *textColor = [KBSkinManager shared].current.keyTextColor ?: [UIColor blackColor];
|
||||
button.iconView.tintColor = button.isSelected ? [UIColor blackColor] : textColor;
|
||||
}
|
||||
|
||||
- (UIColor *)kb_backgroundColorForItem:(KBKeyboardRowItem *)item keyDef:(KBKeyboardKeyDef *)def {
|
||||
NSString *hex = def.backgroundColor;
|
||||
if (hex.length == 0) {
|
||||
hex = [self kb_layoutConfig].defaultKeyBackground;
|
||||
}
|
||||
if (hex.length == 0) { return nil; }
|
||||
return [KBSkinManager colorFromHexString:hex defaultColor:nil];
|
||||
}
|
||||
|
||||
- (CGFloat)kb_metricWidthForKey:(NSString *)key {
|
||||
KBKeyboardLayoutMetrics *m = [self kb_layoutConfig].metrics;
|
||||
if ([key isEqualToString:@"letterWidth"]) { return m.letterWidth.doubleValue; }
|
||||
if ([key isEqualToString:@"controlWidth"]) { return m.controlWidth.doubleValue; }
|
||||
if ([key isEqualToString:@"sendWidth"]) { return m.sendWidth.doubleValue; }
|
||||
if ([key isEqualToString:@"symbolsWideWidth"]) { return m.symbolsWideWidth.doubleValue; }
|
||||
if ([key isEqualToString:@"symbolsSideWidth"]) { return m.symbolsSideWidth.doubleValue; }
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
- (CGFloat)kb_widthForItem:(KBKeyboardRowItem *)item key:(KBKey *)key {
|
||||
CGFloat width = 0.0;
|
||||
if (item.widthValue.doubleValue > 0.0) {
|
||||
width = item.widthValue.doubleValue;
|
||||
} else if (item.width.length > 0) {
|
||||
if ([item.width.lowercaseString isEqualToString:@"flex"]) {
|
||||
return 0.0;
|
||||
}
|
||||
width = [self kb_metricWidthForKey:item.width];
|
||||
if (width <= 0.0) {
|
||||
width = item.width.doubleValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (width <= 0.0) {
|
||||
KBKeyboardLayoutMetrics *m = [self kb_layoutConfig].metrics;
|
||||
if ([item.itemId hasPrefix:@"letter:"] ||
|
||||
[item.itemId hasPrefix:@"digit:"] ||
|
||||
[item.itemId hasPrefix:@"sym:"]) {
|
||||
width = m.letterWidth.doubleValue;
|
||||
} else if (key.type == KBKeyTypeReturn) {
|
||||
width = m.sendWidth.doubleValue;
|
||||
} else if (key.type == KBKeyTypeSpace) {
|
||||
return 0.0;
|
||||
} else {
|
||||
width = m.controlWidth.doubleValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (width <= 0.0) {
|
||||
if ([item.itemId hasPrefix:@"letter:"] ||
|
||||
[item.itemId hasPrefix:@"digit:"] ||
|
||||
[item.itemId hasPrefix:@"sym:"]) {
|
||||
width = 32.0;
|
||||
} else if (key.type == KBKeyTypeReturn) {
|
||||
width = 88.0;
|
||||
} else if (key.type == KBKeyTypeSpace) {
|
||||
return 0.0;
|
||||
} else {
|
||||
width = 41.0;
|
||||
}
|
||||
}
|
||||
|
||||
return width > 0.0 ? [self kb_scaledValue:width] : 0.0;
|
||||
}
|
||||
|
||||
- (CGFloat)kb_fontSizeForItem:(KBKeyboardRowItem *)item key:(KBKey *)key {
|
||||
NSString *fontKey = nil;
|
||||
if ([item.itemId hasPrefix:@"letter:"]) {
|
||||
fontKey = @"letter";
|
||||
} else if ([item.itemId hasPrefix:@"digit:"]) {
|
||||
fontKey = @"digit";
|
||||
} else if ([item.itemId hasPrefix:@"sym:"]) {
|
||||
fontKey = @"symbol";
|
||||
} else {
|
||||
KBKeyboardKeyDef *def = [[self kb_layoutConfig] keyDefForIdentifier:item.itemId];
|
||||
fontKey = def.font;
|
||||
}
|
||||
|
||||
if (fontKey.length == 0) {
|
||||
switch (key.type) {
|
||||
case KBKeyTypeModeChange:
|
||||
case KBKeyTypeSymbolsToggle:
|
||||
fontKey = @"mode";
|
||||
break;
|
||||
case KBKeyTypeSpace:
|
||||
fontKey = @"space";
|
||||
break;
|
||||
case KBKeyTypeReturn:
|
||||
fontKey = @"send";
|
||||
break;
|
||||
default:
|
||||
fontKey = @"symbol";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return [self kb_fontSizeForFontKey:fontKey];
|
||||
}
|
||||
|
||||
- (CGFloat)kb_fontSizeForFontKey:(NSString *)fontKey {
|
||||
KBKeyboardLayoutFonts *fonts = [self kb_layoutConfig].fonts;
|
||||
CGFloat size = 0.0;
|
||||
if ([fontKey isEqualToString:@"letter"]) { size = fonts.letter.doubleValue; }
|
||||
else if ([fontKey isEqualToString:@"digit"]) { size = fonts.digit.doubleValue; }
|
||||
else if ([fontKey isEqualToString:@"symbol"]) { size = fonts.symbol.doubleValue; }
|
||||
else if ([fontKey isEqualToString:@"mode"]) { size = fonts.mode.doubleValue; }
|
||||
else if ([fontKey isEqualToString:@"space"]) { size = fonts.space.doubleValue; }
|
||||
else if ([fontKey isEqualToString:@"send"]) { size = fonts.send.doubleValue; }
|
||||
if (size <= 0.0) { size = 18.0; }
|
||||
return [self kb_scaledValue:size];
|
||||
}
|
||||
|
||||
- (KBKey *)kb_keyForItemId:(NSString *)itemId {
|
||||
if (itemId.length == 0) { return nil; }
|
||||
KBKeyboardKeyDef *def = [[self kb_layoutConfig] keyDefForIdentifier:itemId];
|
||||
if (def) {
|
||||
return [self kb_keyFromDef:def identifier:itemId];
|
||||
}
|
||||
|
||||
NSRange range = [itemId rangeOfString:@":"];
|
||||
if (range.location != NSNotFound) {
|
||||
NSString *prefix = [itemId substringToIndex:range.location];
|
||||
NSString *value = [itemId substringFromIndex:range.location + 1];
|
||||
if ([prefix isEqualToString:@"letter"]) {
|
||||
if (value.length == 1) {
|
||||
return [self kb_letterKeyWithChar:value];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
if ([prefix isEqualToString:@"digit"]) {
|
||||
NSString *identifier = [NSString stringWithFormat:@"digit_%@", value];
|
||||
KBKey *k = [KBKey keyWithIdentifier:identifier title:value output:value type:KBKeyTypeCharacter];
|
||||
k.caseVariant = KBKeyCaseVariantNone;
|
||||
return k;
|
||||
}
|
||||
if ([prefix isEqualToString:@"sym"]) {
|
||||
NSString *identifier = [self kb_identifierForSymbol:value];
|
||||
KBKey *k = [KBKey keyWithIdentifier:identifier title:value output:value type:KBKeyTypeCharacter];
|
||||
k.caseVariant = KBKeyCaseVariantNone;
|
||||
return k;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (KBKey *)kb_keyFromDef:(KBKeyboardKeyDef *)def identifier:(NSString *)identifier {
|
||||
KBKeyType type = [self kb_keyTypeForDef:def];
|
||||
NSString *title = def.title ?: @"";
|
||||
if (type == KBKeyTypeShift && self.shiftOn && def.selectedTitle.length > 0) {
|
||||
title = def.selectedTitle;
|
||||
}
|
||||
NSString *output = @"";
|
||||
switch (type) {
|
||||
case KBKeyTypeSpace:
|
||||
output = @" ";
|
||||
break;
|
||||
case KBKeyTypeReturn:
|
||||
output = @"\n";
|
||||
break;
|
||||
default:
|
||||
output = @"";
|
||||
break;
|
||||
}
|
||||
|
||||
NSString *finalId = identifier;
|
||||
if ([identifier isEqualToString:@"emoji"]) {
|
||||
finalId = KBKeyIdentifierEmojiPanel;
|
||||
} else if ([identifier isEqualToString:@"send"]) {
|
||||
finalId = @"return";
|
||||
}
|
||||
|
||||
KBKey *k = [KBKey keyWithIdentifier:finalId title:title output:output type:type];
|
||||
k.caseVariant = KBKeyCaseVariantNone;
|
||||
return k;
|
||||
}
|
||||
|
||||
- (KBKeyType)kb_keyTypeForDef:(KBKeyboardKeyDef *)def {
|
||||
NSString *type = def.type.lowercaseString;
|
||||
if ([type isEqualToString:@"shift"]) return KBKeyTypeShift;
|
||||
if ([type isEqualToString:@"backspace"]) return KBKeyTypeBackspace;
|
||||
if ([type isEqualToString:@"mode"]) return KBKeyTypeModeChange;
|
||||
if ([type isEqualToString:@"symbolstoggle"]) return KBKeyTypeSymbolsToggle;
|
||||
if ([type isEqualToString:@"space"]) return KBKeyTypeSpace;
|
||||
if ([type isEqualToString:@"return"]) return KBKeyTypeReturn;
|
||||
if ([type isEqualToString:@"globe"]) return KBKeyTypeGlobe;
|
||||
return KBKeyTypeCustom;
|
||||
}
|
||||
|
||||
- (NSString *)kb_identifierForSymbol:(NSString *)symbol {
|
||||
if (symbol.length == 0) { return nil; }
|
||||
static NSDictionary<NSString *, NSString *> *map = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
map = @{
|
||||
@"-": @"sym_minus",
|
||||
@"/": @"sym_slash",
|
||||
@":": @"sym_colon",
|
||||
@";": @"sym_semicolon",
|
||||
@"(": @"sym_paren_l",
|
||||
@")": @"sym_paren_r",
|
||||
@"¥": @"sym_money",
|
||||
@"¥": @"sym_money",
|
||||
@"&": @"sym_amp",
|
||||
@"@": @"sym_at",
|
||||
@"\"": @"sym_quote_double",
|
||||
@"“": @"sym_quote_double",
|
||||
@"”": @"sym_quote_double",
|
||||
@".": @"sym_dot",
|
||||
@",": @"sym_comma",
|
||||
@"?": @"sym_question",
|
||||
@"!": @"sym_exclam",
|
||||
@"'": @"sym_quote_single",
|
||||
@"‘": @"sym_quote_single",
|
||||
@"’": @"sym_quote_single",
|
||||
@"[": @"sym_bracket_l",
|
||||
@"]": @"sym_bracket_r",
|
||||
@"{": @"sym_brace_l",
|
||||
@"}": @"sym_brace_r",
|
||||
@"#": @"sym_hash",
|
||||
@"%": @"sym_percent",
|
||||
@"^": @"sym_caret",
|
||||
@"*": @"sym_asterisk",
|
||||
@"+": @"sym_plus",
|
||||
@"=": @"sym_equal",
|
||||
@"_": @"sym_underscore",
|
||||
@"\\": @"sym_backslash",
|
||||
@"|": @"sym_pipe",
|
||||
@"~": @"sym_tilde",
|
||||
@"<": @"sym_lt",
|
||||
@">": @"sym_gt",
|
||||
@"€": @"sym_euro",
|
||||
@"$": @"sym_dollar",
|
||||
@"·": @"sym_bullet"
|
||||
};
|
||||
});
|
||||
return map[symbol];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (void)onKeyTapped:(KBKeyButton *)sender {
|
||||
|
||||
Reference in New Issue
Block a user