創(chuàng)建Xcode項(xiàng)目
打開Xcode 6以上的版本并創(chuàng)建一個(gè)新項(xiàng)目击吱。
工程命名可以根據(jù)個(gè)人喜好命名淋淀,這里的工程命名為Keyboard遥昧。以其為主項(xiàng)目覆醇,還需要對(duì)項(xiàng)目添加擴(kuò)展朵纷。
添加一個(gè)Text Field,用于彈出自定義鍵盤永脓。在項(xiàng)目中袍辞,打開Main.Storyboard文件,然后在屏幕上的默認(rèn)的視圖控制器上拖放一個(gè)UITextField控件常摧,最好拖放在視圖的上方搅吁,以防彈出的鍵盤將TextField遮擋了,無法查看輸入效果落午。
添加擴(kuò)展
點(diǎn)擊File-> New -> Target谎懦,選擇在iOS/Application
Extension列表中的自定義輸入法(Custom Keyboard)。給該擴(kuò)展命名為CustomKeyboard并選擇Object-C編程語言溃斋。
新建出來的文件夾中有.h/.m文件界拦,我們自定義鍵盤就在這兩個(gè)擴(kuò)展文件上進(jìn)行。
此時(shí)可以直接在模擬器上運(yùn)行了梗劫,在測(cè)試前享甸,首先要對(duì)系統(tǒng)鍵盤進(jìn)行設(shè)置,在模擬器中跳轉(zhuǎn)到主界面梳侨,打開設(shè)置并轉(zhuǎn)到通用->鍵盤->鍵盤蛉威。點(diǎn)擊“添加新鍵盤”,然后選擇CustomKeyboard走哺,這里的鍵盤名字為你的工程名蚯嫌。
但是運(yùn)行的結(jié)果是什么都沒有的,在鍵盤的左下角顯示“Next Keyboard”按鈕丙躏,相當(dāng)于系統(tǒng)默認(rèn)鍵盤上的地球按鈕齐帚,點(diǎn)擊切換輸入法。
添加按鈕
打開文件.h文件彼哼。在這個(gè)文件中对妄,你會(huì)看到一個(gè)類繼承自UIInputViewController。這是管理視圖的鍵盤類敢朱。往該視圖上添加按鈕剪菱,所添加的按鈕就會(huì)在鍵盤中顯示出來。
創(chuàng)建一個(gè)添加按鈕的方法createButtonWithTitle拴签,在此方法中新建UIButton孝常,并根據(jù)個(gè)人喜歡對(duì)button進(jìn)行設(shè)置。參數(shù)title就是各個(gè)按鈕上面顯示的字母蚓哩,稍后通過數(shù)組對(duì)title進(jìn)行傳值构灸。
Button可以使用xib進(jìn)行創(chuàng)建,為了節(jié)省時(shí)間岸梨,這里使用方法來進(jìn)行創(chuàng)建
這個(gè)項(xiàng)目的開發(fā)思路是喜颁,將整個(gè)鍵盤劃分為4行稠氮,每一行的按鈕分別添加到一個(gè)視圖中,即有4個(gè)存放按鈕的視圖半开,最后將4個(gè)視圖添加到Keyboard視圖上隔披。
<p><code>- (UIButton )createButtonWithTitle:(NSString)title{
UIButton*button = [UIButton buttonWithType:(UIButtonTypeSystem)];
button.frame = CGRectMake(0, 0, 20, 30);
[button setTitle:title forState:(UIControlStateNormal)];
[button sizeToFit];
button.titleLabel.font = [UIFont systemFontOfSize:15];
[button setTranslatesAutoresizingMaskIntoConstraints:false];
button.backgroundColor = [UIColor clearColor];
[button setTitleColor:[UIColor darkGrayColor] forState:(UIControlStateNormal)];
[button addTarget:self action:@selector(didTapButton:) forControlEvents:(UIControlEventTouchUpInside)];
returnbutton;
}</code></p>
上述代碼中,button添加一個(gè)方法didTapButton寂拆,此方法用于點(diǎn)擊button時(shí)奢米,獲取button對(duì)應(yīng)輸入的文本內(nèi)容。
觸發(fā)按鈕方法
這里需要獲取用戶點(diǎn)擊哪個(gè)button纠永,根據(jù)不同的按鈕執(zhí)行不同的操作鬓长。如24個(gè)字母鍵就顯示文本內(nèi)容,shift鍵切換大小寫尝江。
同時(shí)也對(duì)字母按鈕與功能按鈕進(jìn)行區(qū)分痢士,可以使用UIInputViewController的屬性textDocumentProxy的一些方法。如insertText就是將內(nèi)容顯示到TextField中茂装,deleteBackward相當(dāng)于退格按鈕怠蹂。
此處功能鍵上的顯示使用英文代替,自己開發(fā)的使用可以使用圖片代替少态。因此切換大小寫會(huì)是全部功能鍵的改變城侧。
<p><code>//獲取點(diǎn)擊按鈕的title
- (void)didTapButton:(UIButton)sender{
NSStringtitle = [sender titleForState:(UIControlStateNormal)];
//響應(yīng)觸摸事件的文本內(nèi)容
if([title isEqualToString:@"cp"] || [title isEqualToString:@"CP"]){
self.isPressShiftKey = !self.isPressShiftKey;
//大小寫轉(zhuǎn)換
[self changeUpOrDown:sender];
}
elseif ([title isEqualToString:@"dp"] || [title isEqualToString:@"DP"]){
[self.textDocumentProxy deleteBackward];
}
elseif ([title isEqualToString:@"Space"]){
[self.textDocumentProxy insertText:@" "];
}
elseif ([title isEqualToString:@"return"]){
[self.textDocumentProxy insertText:@"\n"];
}
elseif ([title isEqualToString:@"next"]){
[self advanceToNextInputMode];
}
else{
[self.textDocumentProxy insertText:title];
}
}</code></p>
添加按鈕約束
一個(gè)全鍵盤樣式的鍵盤上有24個(gè)字母,外加一些特殊的功能鍵彼妻,為了對(duì)按鈕進(jìn)行布局嫌佑,可以使用auto layout,VFL布局還有萬能公式布局侨歉。雖然auto layout可以采用界面添加約束屋摇,但是這么多個(gè)按鈕同時(shí)添加約束,要求添加約束的思路非常清晰幽邓,同時(shí)添加約束的界面可能非撑谖拢卡頓。所以這里使用萬能公式布局牵舵,對(duì)按鈕進(jìn)行一次性的添加約束柒啤。
按鈕布局代碼比較多,只要理清思路就沒問題了畸颅,注意每一個(gè)按鈕之間的關(guān)系担巩。
<p><code>//button約束
-(void)addButtonLayoutConstraint:(NSMutableArray)buttonsandView:(UIView)keyboardView{
for(UIButton *button in buttons) {
//邊距
NSInteger space = 0;
NSInteger index = [buttons indexOfObject:button];
//關(guān)閉button自動(dòng)翻譯約束的功能
button.translatesAutoresizingMaskIntoConstraints = NO;
//萬能代碼約束
//頂部約束
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:buttonattribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:keyboardViewattribute:NSLayoutAttributeTop multiplier:1.0 constant:space];
//底部約束
NSLayoutConstraint *buttomConstraint = [NSLayoutConstraint constraintWithItem:buttonattribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:keyboardViewattribute:NSLayoutAttributeBottom multiplier:1.0 constant:-space];
//右邊約束
NSLayoutConstraint *rightConstraint = nil;
//右邊約束
NSLayoutConstraint *leftConstraint = nil;
//判讀最后一個(gè)button
if (index == buttons.count - 1) {
rightConstraint = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeRightrelatedBy:NSLayoutRelationEqual toItem:keyboardView attribute:NSLayoutAttributeRightmultiplier:1.0 constant:-space];
}
else{
//當(dāng)前button的下一個(gè)button的右約束
UIButton *nextButton = buttons[index + 1];
rightConstraint = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeRightrelatedBy:NSLayoutRelationEqual toItem:nextButton attribute:NSLayoutAttributeLeftmultiplier:1.0 constant:-space];
}
//左約束
if (index == 0) {
leftConstraint = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeLeftrelatedBy:NSLayoutRelationEqual toItem:keyboardView attribute:NSLayoutAttributeLeftmultiplier:1.0 constant:space];
}
else{
UIButton *prevtButton = buttons[index - 1];
leftConstraint = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeLeftrelatedBy:NSLayoutRelationEqual toItem:prevtButton attribute:NSLayoutAttributeRightmultiplier:1.0 constant:space];
}
//等寬
UIButton *firstButton = buttons[0];
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:firstButtonattribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:button attribute:NSLayoutAttributeWidthmultiplier:1.0 constant:0];
[keyboardView addConstraint:widthConstraint];
[keyboardView addConstraints:@[topConstraint,buttomConstraint,rightConstraint,leftConstraint]];
}
}</code></p>
添加每一列約束
方法addRowsLayoutConstraint對(duì)每一行存儲(chǔ)按鈕的視圖添加約束,這里要注意的是當(dāng)前行没炒、上一行與下一行之間的關(guān)系涛癌,其實(shí)與為button添加約束類似。
<p><code>//row約束
-(void)addRowsLayoutConstraint:(NSArray)rowsandView:(UIView)inputView{
for(UIView *rowView in rows) {
NSInteger space = 0;
NSInteger index = [rows indexOfObject:rowView];
rowView.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:rowViewattribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:inputViewattribute:NSLayoutAttributeRight multiplier:1.0 constant:-space];
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:rowViewattribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:inputViewattribute:NSLayoutAttributeLeft multiplier:1.0 constant:space];
//頂部約束
NSLayoutConstraint *topConstraint = nil;
if (index == 0) {
topConstraint = [NSLayoutConstraint constraintWithItem:rowView attribute:NSLayoutAttributeToprelatedBy:NSLayoutRelationEqual toItem:inputView attribute:NSLayoutAttributeTopmultiplier:1.0 constant:0];
}
else{
UIView *prevtRow = rows[index - 1];
topConstraint = [NSLayoutConstraint constraintWithItem:rowView attribute:NSLayoutAttributeToprelatedBy:NSLayoutRelationEqual toItem:prevtRow attribute:NSLayoutAttributeBottommultiplier:1.0 constant:0];
}
//底部約束
NSLayoutConstraint *buttomConstraint = nil;
if (index == rows.count - 1) {
buttomConstraint = [NSLayoutConstraint constraintWithItem:rowView attribute:NSLayoutAttributeBottomrelatedBy:NSLayoutRelationEqual toItem:inputView attribute:NSLayoutAttributeBottommultiplier:1.0 constant:0];
}
else{
UIView *nextRow = rows[index + 1];
buttomConstraint = [NSLayoutConstraint constraintWithItem:rowView attribute:NSLayoutAttributeBottomrelatedBy:NSLayoutRelationEqual toItem:nextRow attribute:NSLayoutAttributeTop multiplier:1.0constant:0];
}
//等高約束
UIView *firstRow = rows[0];
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:firstRowattribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:rowViewattribute:NSLayoutAttributeHeight multiplier:1.0 constant:0];
[inputView addConstraint:heightConstraint];
[inputView addConstraints:@[leftConstraint,rightConstraint,topConstraint,buttomConstraint]];
}
}</code></p>
按鈕添加對(duì)應(yīng)的字符或者功能
對(duì)數(shù)組參數(shù)上的buttonTitles進(jìn)行遍歷,即按鈕上顯示的字符拳话,數(shù)組中字符串個(gè)數(shù)來創(chuàng)建按鈕先匪。
使用一個(gè)帶參的方法createRowOfButtons,將已經(jīng)存儲(chǔ)在數(shù)組里面的字母或符號(hào)添加到按鈕上假颇,這里的數(shù)組分別是根據(jù)每一行的內(nèi)容存儲(chǔ)的,即有4個(gè)存儲(chǔ)字母或符號(hào)的數(shù)組骨稿。同時(shí)也創(chuàng)建一個(gè)存放按鈕的視圖笨鸡,并且對(duì)按鈕與視圖之間的約束進(jìn)行設(shè)置。使用數(shù)組將全部的鍵存儲(chǔ)起來坦冠,一行一個(gè)數(shù)組形耗。最后將數(shù)組buttons存放在一個(gè)總的數(shù)組allButtons中,用于之后遍歷鍵盤上的所有按鈕辙浑,進(jìn)行大小寫轉(zhuǎn)換激涤。
<p><code>//創(chuàng)建一行button
- (UIView )createRowOfButtons:(NSArray)buttonTitles{
NSMutableArraybuttons = [NSMutableArray array];
//行視圖寬高
UIViewkeyBoardRowView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
//遍歷button
for(NSString *title in buttonTitles) {
//調(diào)用createButtonWithTitle
UIButton *button = [self createButtonWithTitle:title];
//將button添加到數(shù)組中
[buttons addObject:button];
[keyBoardRowView addSubview:button];
}
[self.allButtonsaddObject:buttons];
//調(diào)用約束
[selfaddButtonLayoutConstraint:buttons andView:keyBoardRowView];
returnkeyBoardRowView;
}</code></p>
顯示
最后在viewDidLoad上,將顯示字符數(shù)組添加到按鈕上判呕,并將每一行視圖添加到Keyboard視圖上倦踢,對(duì)每一行添加約束。
<p><code>- (void)viewDidLoad {
[superviewDidLoad];
self.allButtons= [NSMutableArray array];
self.isPressShiftKey= NO;
self.firstButtonRow= [NSMutableArray arrayWithObjects:@"q",@"w",@"e",@"r",@"t",@"y",@"u",@"i",@"o",@"p",nil];
self.secondButtonRow= [NSMutableArray arrayWithObjects:@"a",@"s",@"d",@"f",@"g",@"h",@"j",@"k",@"l",nil];
self.thirdButtonRow= [NSMutableArray arrayWithObjects:@"cp",@"z",@"x",@"c",@"v",@"b",@"n",@"m",@"dp",nil];
self.forthButtonRow= [NSMutableArray arrayWithObjects:@"123",@"next",@"Space",@"ch/en",@"return",nil];
UIViewFirstRow = [self createRowOfButtons:self.firstButtonRow];
UIViewSecndRow = [self createRowOfButtons:self.secondButtonRow];
UIViewThirdRow = [self createRowOfButtons:self.thirdButtonRow];
UIViewforthRow = [self createRowOfButtons:self.forthButtonRow];
NSArray*rows = @[FirstRow,SecndRow,ThirdRow,forthRow];
[self.viewaddSubview:FirstRow];
[self.viewaddSubview:SecndRow];
[self.viewaddSubview:ThirdRow];
[self.viewaddSubview:forthRow];
[selfaddRowsLayoutConstraint:rows andView:self.view];
}</code></p>
大小寫切換
點(diǎn)擊大小寫按鈕侠草,觸發(fā)changeUpOrDown方法辱挥,大小寫轉(zhuǎn)換就要用到上面說的allButtons數(shù)組了,遍歷全部的按鈕边涕,獲取按鈕上的title晤碘,并判斷按鈕當(dāng)前是出于什么狀態(tài)(大寫或小寫),在對(duì)title進(jìn)行字符串大小寫轉(zhuǎn)換功蜓,最后為按鈕設(shè)置title园爷。
//大小寫轉(zhuǎn)換
<p><code>- (void)changeUpOrDown:(UIButton*)shiftKey{
for(NSArray * buttons in self.allButtons) {
for (UIButton *button in buttons) {
NSString *title = [button titleForState:UIControlStateNormal];
if (self.isPressShiftKey) {
title = [title uppercaseString];
}
else{
title = [title lowercaseString];
}
[button setTitle:title forState:(UIControlStateNormal)];
}
}
}</code></p>
最后再說兩句
這個(gè)教程只能實(shí)現(xiàn)簡單的功能,同時(shí)代碼中存在一些不完善的地方式撼,只供參考童社,還是需要大家的努力。
完整代碼的下載地址:vancef/CustomKeyboard · GitHub