iOS8自定義鍵盤-Object-C

創(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{
    NSString
    title = [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];
    //行視圖寬高
    UIView
    keyBoardRowView = [[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];
UIView
SecndRow = [self createRowOfButtons:self.secondButtonRow];
UIViewThirdRow = [self createRowOfButtons:self.thirdButtonRow];
UIView
forthRow = [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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末著隆,一起剝皮案震驚了整個(gè)濱河市叠洗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌旅东,老刑警劉巖灭抑,帶你破解...
    沈念sama閱讀 221,888評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異抵代,居然都是意外死亡腾节,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來案腺,“玉大人庆冕,你說我怎么就攤上這事∨ィ” “怎么了访递?”我有些...
    開封第一講書人閱讀 168,386評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長同辣。 經(jīng)常有香客問我拷姿,道長,這世上最難降的妖魔是什么旱函? 我笑而不...
    開封第一講書人閱讀 59,726評(píng)論 1 297
  • 正文 為了忘掉前任响巢,我火速辦了婚禮,結(jié)果婚禮上棒妨,老公的妹妹穿的比我還像新娘踪古。我一直安慰自己,他們只是感情好券腔,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評(píng)論 6 397
  • 文/花漫 我一把揭開白布伏穆。 她就那樣靜靜地躺著,像睡著了一般纷纫。 火紅的嫁衣襯著肌膚如雪蜈出。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,337評(píng)論 1 310
  • 那天涛酗,我揣著相機(jī)與錄音铡原,去河邊找鬼。 笑死商叹,一個(gè)胖子當(dāng)著我的面吹牛燕刻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播剖笙,決...
    沈念sama閱讀 40,902評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼卵洗,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了弥咪?” 一聲冷哼從身側(cè)響起过蹂,我...
    開封第一講書人閱讀 39,807評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎聚至,沒想到半個(gè)月后酷勺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,349評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扳躬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評(píng)論 3 340
  • 正文 我和宋清朗相戀三年脆诉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了甚亭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,567評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡击胜,死狀恐怖亏狰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情偶摔,我是刑警寧澤暇唾,帶...
    沈念sama閱讀 36,242評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站辰斋,受9級(jí)特大地震影響策州,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜亡呵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評(píng)論 3 334
  • 文/蒙蒙 一抽活、第九天 我趴在偏房一處隱蔽的房頂上張望硫戈。 院中可真熱鬧锰什,春花似錦、人聲如沸丁逝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽霜幼。三九已至嫩码,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間罪既,已是汗流浹背铸题。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留琢感,地道東北人丢间。 一個(gè)月前我還...
    沈念sama閱讀 48,995評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像驹针,于是被迫代替她去往敵國和親烘挫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容