1
This commit is contained in:
255
CustomKeyboard/View/KBKeyboardView.m
Normal file
255
CustomKeyboard/View/KBKeyboardView.m
Normal file
@@ -0,0 +1,255 @@
|
||||
//
|
||||
// KBKeyboardView.m
|
||||
// CustomKeyboard
|
||||
//
|
||||
|
||||
#import "KBKeyboardView.h"
|
||||
#import "KBKeyButton.h"
|
||||
#import "KBKey.h"
|
||||
|
||||
@interface KBKeyboardView ()
|
||||
@property (nonatomic, strong) UIView *row1;
|
||||
@property (nonatomic, strong) UIView *row2;
|
||||
@property (nonatomic, strong) UIView *row3;
|
||||
@property (nonatomic, strong) UIView *row4;
|
||||
@property (nonatomic, strong) NSArray<NSArray<KBKey *> *> *keysForRows;
|
||||
@end
|
||||
|
||||
@implementation KBKeyboardView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
self.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1.0];
|
||||
_layoutStyle = KBKeyboardLayoutStyleLetters;
|
||||
_shiftOn = YES; // 初始使用大写,贴近截图效果
|
||||
[self buildBase];
|
||||
[self reloadKeys];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)buildBase {
|
||||
[self addSubview:self.row1];
|
||||
[self addSubview:self.row2];
|
||||
[self addSubview:self.row3];
|
||||
[self addSubview:self.row4];
|
||||
|
||||
CGFloat vSpacing = 8;
|
||||
[self.row1 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.mas_top).offset(8);
|
||||
make.left.right.equalTo(self);
|
||||
make.height.mas_equalTo(44);
|
||||
}];
|
||||
[self.row2 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.row1.mas_bottom).offset(vSpacing);
|
||||
make.left.right.equalTo(self);
|
||||
make.height.equalTo(self.row1);
|
||||
}];
|
||||
[self.row3 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.row2.mas_bottom).offset(vSpacing);
|
||||
make.left.right.equalTo(self);
|
||||
make.height.equalTo(self.row1);
|
||||
}];
|
||||
[self.row4 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.row3.mas_bottom).offset(vSpacing);
|
||||
make.left.right.equalTo(self);
|
||||
make.height.equalTo(self.row1);
|
||||
make.bottom.equalTo(self.mas_bottom).offset(-6);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)reloadKeys {
|
||||
// 移除旧按钮
|
||||
for (UIView *row in @[self.row1, self.row2, self.row3, self.row4]) {
|
||||
[row.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
}
|
||||
|
||||
self.keysForRows = [self buildKeysForCurrentLayout];
|
||||
[self buildRow:self.row1 withKeys:self.keysForRows[0]];
|
||||
// 第二行:字母布局时通过左右等宽占位让整行居中
|
||||
CGFloat row2Spacer = (self.layoutStyle == KBKeyboardLayoutStyleLetters) ? 0.5 : 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]];
|
||||
}
|
||||
|
||||
- (NSArray<NSArray<KBKey *> *> *)buildKeysForCurrentLayout {
|
||||
if (self.layoutStyle == KBKeyboardLayoutStyleNumbers) {
|
||||
// 数字/符号布局:3 行主键 + 底部控制行
|
||||
NSArray *r1 = @[
|
||||
[KBKey keyWithTitle:@"1" output:@"1"], [KBKey keyWithTitle:@"2" output:@"2"], [KBKey keyWithTitle:@"3" output:@"3"],
|
||||
[KBKey keyWithTitle:@"4" output:@"4"], [KBKey keyWithTitle:@"5" output:@"5"], [KBKey keyWithTitle:@"6" output:@"6"],
|
||||
[KBKey keyWithTitle:@"7" output:@"7"], [KBKey keyWithTitle:@"8" output:@"8"], [KBKey keyWithTitle:@"9" output:@"9"], [KBKey keyWithTitle:@"0" output:@"0"],
|
||||
];
|
||||
NSArray *r2 = @[
|
||||
[KBKey keyWithTitle:@"-" output:@"-"], [KBKey keyWithTitle:@"/" output:@"/"], [KBKey keyWithTitle:@":" output:@":"],
|
||||
[KBKey keyWithTitle:@";" output:@";"], [KBKey keyWithTitle:@"(" output:@"("], [KBKey keyWithTitle:@")" output:@")"],
|
||||
[KBKey keyWithTitle:@"$" output:@"$"], [KBKey keyWithTitle:@"&" output:@"&"], [KBKey keyWithTitle:@"@" output:@"@"], [KBKey keyWithTitle:@"\"" output:@"\""],
|
||||
];
|
||||
NSArray *r3 = @[
|
||||
[KBKey keyWithTitle:@"#+=" type:KBKeyTypeModeChange],
|
||||
[KBKey keyWithTitle:@"," output:@","], [KBKey keyWithTitle:@"." output:@"."], [KBKey keyWithTitle:@"?" output:@"?"],
|
||||
[KBKey keyWithTitle:@"!" output:@"!"], [KBKey keyWithTitle:@"'" output:@"'"],
|
||||
[KBKey keyWithTitle:@"⌫" type:KBKeyTypeBackspace],
|
||||
];
|
||||
NSArray *r4 = @[
|
||||
[KBKey keyWithTitle:@"ABC" type:KBKeyTypeModeChange],
|
||||
[KBKey keyWithTitle:@"," output:@","],
|
||||
[KBKey keyWithTitle:@"space" type:KBKeyTypeSpace],
|
||||
[KBKey keyWithTitle:@"中/英" type:KBKeyTypeCustom],
|
||||
[KBKey keyWithTitle:@"发送" type:KBKeyTypeReturn],
|
||||
];
|
||||
return @[r1, r2, r3, r4];
|
||||
}
|
||||
|
||||
// 字母布局(QWERTY)
|
||||
NSArray *r1 = @[ @"Q", @"W", @"E", @"R", @"T", @"Y", @"U", @"I", @"O", @"P" ];
|
||||
NSArray *r2 = @[ @"A", @"S", @"D", @"F", @"G", @"H", @"J", @"K", @"L" ];
|
||||
NSArray *r3chars = @[ @"Z", @"X", @"C", @"V", @"B", @"N", @"M" ];
|
||||
|
||||
NSMutableArray *row1 = [NSMutableArray arrayWithCapacity:r1.count];
|
||||
for (NSString *s in r1) { [row1 addObject:[KBKey keyWithTitle:s output:(self.shiftOn ? s : s.lowercaseString)]]; }
|
||||
|
||||
NSMutableArray *row2 = [NSMutableArray arrayWithCapacity:r2.count];
|
||||
for (NSString *s in r2) { [row2 addObject:[KBKey keyWithTitle:s output:(self.shiftOn ? s : s.lowercaseString)]]; }
|
||||
|
||||
NSMutableArray *row3 = [NSMutableArray array];
|
||||
[row3 addObject:[KBKey keyWithTitle:@"⇧" type:KBKeyTypeShift]];
|
||||
for (NSString *s in r3chars) { [row3 addObject:[KBKey keyWithTitle:s output:(self.shiftOn ? s : s.lowercaseString)]]; }
|
||||
[row3 addObject:[KBKey keyWithTitle:@"⌫" type:KBKeyTypeBackspace]];
|
||||
|
||||
NSArray *row4 = @[ [KBKey keyWithTitle:@"123" type:KBKeyTypeModeChange],
|
||||
[KBKey keyWithTitle:@"," output:@","],
|
||||
[KBKey keyWithTitle:@"space" type:KBKeyTypeSpace],
|
||||
[KBKey keyWithTitle:@"中/英" type:KBKeyTypeCustom],
|
||||
[KBKey keyWithTitle:@"发送" type:KBKeyTypeReturn] ];
|
||||
|
||||
return @[row1.copy, row2.copy, row3.copy, row4];
|
||||
}
|
||||
|
||||
- (void)buildRow:(UIView *)row withKeys:(NSArray<KBKey *> *)keys {
|
||||
[self buildRow:row withKeys:keys edgeSpacerMultiplier:0.0];
|
||||
}
|
||||
|
||||
- (void)buildRow:(UIView *)row withKeys:(NSArray<KBKey *> *)keys edgeSpacerMultiplier:(CGFloat)edgeSpacerMultiplier {
|
||||
CGFloat hInset = 6; // 行左右内边距
|
||||
CGFloat spacing = 6; // 键与键之间的间距
|
||||
UIView *previous = nil;
|
||||
UIView *leftSpacer = nil;
|
||||
UIView *rightSpacer = nil;
|
||||
if (edgeSpacerMultiplier > 0.0) {
|
||||
leftSpacer = [UIView new];
|
||||
rightSpacer = [UIView new];
|
||||
leftSpacer.backgroundColor = [UIColor clearColor];
|
||||
rightSpacer.backgroundColor = [UIColor clearColor];
|
||||
[row addSubview:leftSpacer];
|
||||
[row addSubview:rightSpacer];
|
||||
[leftSpacer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(row.mas_left).offset(hInset);
|
||||
make.centerY.equalTo(row);
|
||||
make.height.mas_equalTo(1);
|
||||
}];
|
||||
[rightSpacer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(row.mas_right).offset(-hInset);
|
||||
make.centerY.equalTo(row);
|
||||
make.height.mas_equalTo(1);
|
||||
}];
|
||||
}
|
||||
for (NSInteger i = 0; i < keys.count; i++) {
|
||||
KBKey *key = keys[i];
|
||||
KBKeyButton *btn = [[KBKeyButton alloc] init];
|
||||
btn.key = key;
|
||||
[btn setTitle:key.title forState:UIControlStateNormal];
|
||||
[btn addTarget:self action:@selector(onKeyTapped:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[row addSubview:btn];
|
||||
|
||||
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.bottom.equalTo(row);
|
||||
if (previous) {
|
||||
make.left.equalTo(previous.mas_right).offset(spacing);
|
||||
} else {
|
||||
if (leftSpacer) {
|
||||
make.left.equalTo(leftSpacer.mas_right).offset(spacing);
|
||||
} else {
|
||||
make.left.equalTo(row.mas_left).offset(hInset);
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
// 宽度规则:字符键等宽;特殊键按倍数放大
|
||||
if (key.type == KBKeyTypeCharacter) {
|
||||
if (previous && previous != nil) {
|
||||
if (((KBKeyButton *)previous).key.type == KBKeyTypeCharacter) {
|
||||
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.equalTo(previous);
|
||||
}];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// special keys: give 1.5x of a character key by deferring constraint equalities after loop
|
||||
}
|
||||
|
||||
previous = btn;
|
||||
}
|
||||
// 右侧使用内边距或右占位
|
||||
[previous mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
if (rightSpacer) {
|
||||
make.right.equalTo(rightSpacer.mas_left).offset(-spacing);
|
||||
} else {
|
||||
make.right.equalTo(row.mas_right).offset(-hInset);
|
||||
}
|
||||
}];
|
||||
|
||||
// 第二遍:以首个字符键为基准,统一设置特殊键宽度倍数
|
||||
KBKeyButton *firstChar = nil;
|
||||
for (KBKeyButton *b in row.subviews) {
|
||||
if ([b isKindOfClass:[KBKeyButton class]] && b.key.type == KBKeyTypeCharacter) { firstChar = b; break; }
|
||||
}
|
||||
if (firstChar) {
|
||||
for (KBKeyButton *b in row.subviews) {
|
||||
if (![b isKindOfClass:[KBKeyButton class]]) continue;
|
||||
if (b.key.type == KBKeyTypeCharacter) continue;
|
||||
CGFloat multiplier = 1.5;
|
||||
if (b.key.type == KBKeyTypeSpace) multiplier = 4.0;
|
||||
if (b.key.type == KBKeyTypeReturn) multiplier = 1.8;
|
||||
if (b.key.type == KBKeyTypeModeChange || b.key.type == KBKeyTypeGlobe || b.key.type == KBKeyTypeShift || b.key.type == KBKeyTypeBackspace) {
|
||||
multiplier = 1.5;
|
||||
}
|
||||
[b mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.equalTo(firstChar).multipliedBy(multiplier);
|
||||
}];
|
||||
}
|
||||
// 如果有左右占位,则把占位宽度设置为字符键宽度的一定倍数,以实现整体居中
|
||||
if (leftSpacer && rightSpacer) {
|
||||
[leftSpacer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.equalTo(firstChar).multipliedBy(edgeSpacerMultiplier);
|
||||
}];
|
||||
[rightSpacer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.equalTo(firstChar).multipliedBy(edgeSpacerMultiplier);
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (void)onKeyTapped:(KBKeyButton *)sender {
|
||||
KBKey *key = sender.key;
|
||||
if (key.type == KBKeyTypeShift) {
|
||||
self.shiftOn = !self.shiftOn;
|
||||
[self reloadKeys];
|
||||
return;
|
||||
}
|
||||
if ([self.delegate respondsToSelector:@selector(keyboardView:didTapKey:)]) {
|
||||
[self.delegate keyboardView:self didTapKey:key];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Lazy
|
||||
|
||||
- (UIView *)row1 { if (!_row1) _row1 = [UIView new]; return _row1; }
|
||||
- (UIView *)row2 { if (!_row2) _row2 = [UIView new]; return _row2; }
|
||||
- (UIView *)row3 { if (!_row3) _row3 = [UIView new]; return _row3; }
|
||||
- (UIView *)row4 { if (!_row4) _row4 = [UIView new]; return _row4; }
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user