下面的東西是編寫自定義的表情鍵盤,話不多說,開門見山吧!下面主要用到的知識有MVC, iOS開發中的自動佈局,自定義元件的封裝與使用,Block回撥,CoreData的使用。有的小夥伴可能會問寫一個自定義表情鍵盤腫麼這麼麻煩?下面將會介紹我們如何用上面提到的東西來定義我們的表情鍵盤。下面的內容會比較多,這篇博文還是比較有料的。
還是那句話寫技術部落格是少不了程式碼的,下面會結合程式碼來回顧一下iOS的知識,本篇博文中用到的知識點在前面的部落格中都能找到相應的內容,本篇算是一個小小的功能整合。先來張圖看一下本app的目錄結構。我是根據自己對MVC的理解來構建的目錄結構,希望起到拋磚引玉的作用,有好的解決方案歡迎評論或者留言指出。Face檔案中存放的時我們的表情圖片,Model檔案封裝的是從sqlite中讀取歷史頭像的元件,View檔案中封裝的時我們自定義的元件,也就是自定義鍵盤相關的檢視,Controller負責將我們的各個元件組裝到一起完成我們想要的功能。下面會一一介紹。
上面是檔案的組織結構,下面為了更為直觀的瞭解我們想要的效果,下面先看幾張截圖,來直觀的感受一下執行效果,上面是豎屏的顯示效果,下面是橫屏的顯示效果。因為在封裝自定義鍵盤中用到了自動佈局所以橫屏顯示或者在更大的螢幕上顯示是沒問題的,常用表情是使用者用過的表情,然後存在Sqlite中,顯示時並按時間降序排列。more是用來擴充套件功能用的介面。話不多說,來的程式碼才是實在的。
一.View(自定義檢視)
View資料夾下存放的時我們自定義的檢視元件,因為是自定義的元件所以storyboard我們就用不了啦,所有的程式碼都必須手寫,這樣才能保證元件使用的靈活性和減少各個元件之間的耦合性,更利於團隊之間的合作。在封裝元件時要預留好外界可能使用到的介面,和返回該返回的資料。好啦,廢話少說,來點乾貨吧!
1、FaceView元件的封裝:FaceView即負責顯示一個個的頭像。在使用該元件時要傳入要顯示的圖片和圖片對應的文字(如【哈哈】),當點選圖片的時候,會通過block回撥的形式把該圖片的image以及圖片文字返回到使用的元件中去,下面是關鍵程式碼:
FaceView.h中的程式碼如下(下面程式碼是定義啦相應的Block型別和對外的介面):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#import 2 //宣告表情對應的block,用於把點選的表情的圖片和圖片資訊傳到上層檢視 typedef void (^FaceBlock) (UIImage *image, NSString *imageText); @interface FaceView : UIView //圖片對應的文字 @property (nonatomic, strong) NSString *imageText; //表情圖片 @property (nonatomic, strong) UIImage *headerImage; //設定block回撥 -(void)setFaceBlock:(FaceBlock)block; //設定圖片,文字 -(void)setImage:(UIImage *) image ImageText:(NSString *) text; @end |
FaceView.m中的程式碼如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
// // FaceView.m // MyKeyBoard // // Created by 青玉伏案 on 14-9-16. // Copyright (c) 2014年 Mrli. All rights reserved. // #import "FaceView.h" @interface FaceView () @property(strong, nonatomic) FaceBlock block; @property (strong, nonatomic) UIImageView *imageView; @end @implementation FaceView //初始化圖片 - (id)initWithFrame:(CGRect)frame { //face的大小 frame.size.height = 30; frame.size.width = 30; self = [super initWithFrame:frame]; if (self) { self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)]; [self addSubview:self.imageView]; } return self; } -(void) setFaceBlock:(FaceBlock)block { self.block = block; } -(void) setImage:(UIImage *)image ImageText:(NSString *)text { //顯示圖片 [self.imageView setImage:image]; //把圖片儲存起來 self.headerImage = image; self.imageText = text; } //點選時回撥 -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint point = [touch locationInView:self]; //判斷觸控的結束點是否在圖片中 if (CGRectContainsPoint(self.bounds, point)) { //回撥,把該頭像的資訊傳到相應的controller中 self.block(self.headerImage, self.imageText); } } @end |
程式碼說明:
主要就是block回撥的使用,就是封裝了一個自定義的button,具體內容請參考之前的部落格“IOS開發之自定義Button(整合三種回撥模式)”
2、FunctionView元件的封裝,FunctionView就是使用FaceView元件和ScrollView元件把表情載入進來,在例項化FunctionView元件時,我們用到了自動佈局來設定ScrollView和下面的Button
FunctionView.h的程式碼如下,在.h中留有元件的介面和回撥用的Block, plistFileName用於載入我們的資原始檔時使用,至於如何使用plist檔案,請參考之前的部落格:IOS開發之顯示微博表情
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// // FunctionView.h // MyKeyBoard // // Created by 青玉伏案 on 14-9-16. // Copyright (c) 2014年 Mrli. All rights reserved. // #import 10 //定義對應的block型別,用於資料的互動 typedef void (^FunctionBlock) (UIImage *image, NSString *imageText); @interface FunctionView : UIView //資原始檔名 @property (nonatomic, strong) NSString *plistFileName; //接受block塊 -(void)setFunctionBlock:(FunctionBlock) block; @end |
FunctionView.m中的程式碼如下,常用表情是在sqlite中獲取的,而全部表情是通過plist檔案的資訊在Face檔案中載入的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
// // FunctionView.m // MyKeyBoard // // Created by 青玉伏案 on 14-9-16. // Copyright (c) 2014年 Mrli. All rights reserved. // #import "FunctionView.h" #import "FaceView.h" #import "ImageModelClass.h" #import "HistoryImage.h" @interface FunctionView() @property (strong, nonatomic) FunctionBlock block; //暫存表情元件回撥的表情和表情文字 @property (strong, nonatomic) UIImage *headerImage; @property (strong, nonatomic) NSString *imageText; //display我們的表情圖片 @property (strong, nonatomic) UIScrollView *headerScrollView; //定義資料模型用於獲取歷史表情 @property (strong, nonatomic) ImageModelClass *imageModel; @end @implementation FunctionView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { //例項化資料模型 self.imageModel =[[ImageModelClass alloc] init]; //例項化下面的button UIButton *faceButton = [[UIButton alloc] initWithFrame:CGRectZero]; faceButton.backgroundColor = [UIColor grayColor]; [faceButton setTitle:@"全部表情" forState:UIControlStateNormal]; [faceButton setShowsTouchWhenHighlighted:YES]; [faceButton addTarget:self action:@selector(tapButton1:) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:faceButton]; //例項化常用表情按鈕 UIButton *moreButton = [[UIButton alloc] initWithFrame:CGRectZero]; moreButton.backgroundColor = [UIColor orangeColor]; [moreButton setTitle:@"常用表情" forState:UIControlStateNormal]; [moreButton setShowsTouchWhenHighlighted:YES]; [moreButton addTarget:self action:@selector(tapButton2:) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:moreButton]; //給按鈕新增約束 faceButton.translatesAutoresizingMaskIntoConstraints = NO; moreButton.translatesAutoresizingMaskIntoConstraints = NO; //水平約束 NSArray *buttonH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[faceButton][moreButton(==faceButton)]|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(faceButton,moreButton)]; [self addConstraints:buttonH]; //垂直約束 NSArray *button1V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[faceButton(44)]|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(faceButton)]; [self addConstraints:button1V]; NSArray *button2V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[moreButton(44)]|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(moreButton)]; [self addConstraints:button2V]; //預設顯示錶情圖片 [self tapButton1:nil]; } return self; } //接受回撥 -(void)setFunctionBlock:(FunctionBlock)block { self.block = block; } //點選全部表情按鈕回撥方法 -(void)tapButton1: (id) sender { // 從plist檔案載入資源 NSBundle *bundle = [NSBundle mainBundle]; NSString *path = [bundle pathForResource:self.plistFileName ofType:@"plist"]; NSArray *headers = [NSArray arrayWithContentsOfFile:path]; if (headers.count == 0) { NSLog(@"訪問的plist檔案不存在"); } else { //呼叫headers方法顯示錶情 [self header:headers]; } } //點選歷史表情的回撥方法 -(void) tapButton2: (id) sender { //從資料庫中查詢所有的圖片 NSArray *imageData = [self.imageModel queryAll]; //解析請求到的資料 NSMutableArray *headers = [NSMutableArray arrayWithCapacity:imageData.count]; //資料實體,相當於javaBean的東西 HistoryImage *tempData; for (int i = 0; i < imageData.count; i ++) { tempData = imageData[i]; //解析資料,轉換成函式headers要用的資料格式 NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:2]; [dic setObject:tempData.imageText forKey:@"chs"]; UIImage *image = [UIImage imageWithData:tempData.headerImage]; [dic setObject:image forKey:@"png"]; [headers addObject:dic]; } [self header:headers]; } //負責把查出來的圖片顯示 -(void) header:(NSArray *)headers { [self.headerScrollView removeFromSuperview]; self.headerScrollView = [[UIScrollView alloc] initWithFrame:CGRectZero]; [self addSubview:self.headerScrollView]; //給scrollView新增約束 self.headerScrollView.translatesAutoresizingMaskIntoConstraints = NO; //水平約束 NSArray *scrollH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[_headerScrollView]-10-|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(_headerScrollView)]; [self addConstraints:scrollH]; //垂直約束 NSArray *scrolV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-10-[_headerScrollView]-50-|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(_headerScrollView)]; [self addConstraints:scrolV]; CGFloat scrollHeight = (self.frame).size.height-60; //根據圖片量來計算scrollView的Contain的寬度 CGFloat width = (headers.count/(scrollHeight/30))*30; self.headerScrollView.contentSize = CGSizeMake(width, scrollHeight); self.headerScrollView.pagingEnabled = YES; //圖片座標 CGFloat x = 0; CGFloat y = 0; //往scroll上貼圖片 for (int i = 0; i < headers.count; i ++) { //獲取圖片資訊 UIImage *image; if ([headers[i][@"png"] isKindOfClass:[NSString class]]) { image = [UIImage imageNamed:headers[i][@"png"]]; } else { image = headers[i][@"png"]; } NSString *imageText = headers[i][@"chs"]; //計算圖片位置 y = (i%(int)(scrollHeight/30)) * 30; x = (i/(int)(scrollHeight/30)) * 30; FaceView *face = [[FaceView alloc] initWithFrame:CGRectMake(x, y, 0, 0)]; [face setImage:image ImageText:imageText]; //face的回撥,當face點選時獲取face的圖片 __weak __block FunctionView *copy_self = self; [face setFaceBlock:^(UIImage *image, NSString *imageText) { copy_self.block(image, imageText); }]; [self.headerScrollView addSubview:face]; } [self.headerScrollView setNeedsDisplay]; } @end |
View Code
程式碼說明:
1、主要是通過對資原始檔或者對從資料庫中查詢的資源進行遍歷然後新增到ScrollView中
2.為了適應不同的螢幕給相應的元件新增了約束
3.ToolView元件的封裝: ToolView就是在主螢幕上下面的類似於TabBar的東西,當鍵盤出來的時候,ToolView會運動到鍵盤上面的位置。為了使用不同的螢幕,也需要用自動佈局來實現。
ToolView.h的程式碼如下:預留元件介面和宣告block型別
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// // ToolView.h // MyKeyBoard // // Created by 青玉伏案 on 14-9-16. // Copyright (c) 2014年 Mrli. All rights reserved. // /***************** 封裝下面的工具條元件 *****************/ #import <UIKit/UIKit.h> //定義block塊變數型別,用於回撥,把本View上的按鈕的index傳到Controller中 typedef void (^ToolIndex) (NSInteger index); @interface ToolView : UIView //塊變數型別的setter方法 -(void)setToolIndex:(ToolIndex) toolBlock; @end |
ToolView.m的程式碼實現:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
// // ToolView.m // MyKeyBoard // // Created by 青玉伏案 on 14-9-16. // Copyright (c) 2014年 Mrli. All rights reserved. // #import "ToolView.h" @interface ToolView () //定義ToolIndex型別的block,用於接受外界傳過來的block @property (nonatomic, strong) ToolIndex myBlock; @end @implementation ToolView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { //1初始化表情按鈕 UIButton *faceButton = [[UIButton alloc] initWithFrame:CGRectZero]; faceButton.backgroundColor = [UIColor orangeColor]; [faceButton setTitle:@"表情" forState:UIControlStateNormal]; [faceButton setShowsTouchWhenHighlighted:YES]; [faceButton addTarget:self action:@selector(tapFaceButton:) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:faceButton]; //初始化更多按鈕 UIButton *moreButton = [[UIButton alloc] initWithFrame:CGRectZero]; moreButton.backgroundColor = [UIColor grayColor]; [moreButton setTitle:@"More" forState:UIControlStateNormal]; [moreButton setShowsTouchWhenHighlighted:YES]; [moreButton addTarget:self action:@selector(tapMoreButton:) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:moreButton]; //給我們的按鈕新增約束來讓按鈕來佔滿toolView; faceButton.translatesAutoresizingMaskIntoConstraints = NO; moreButton.translatesAutoresizingMaskIntoConstraints = NO; //新增水平約束 NSArray *buttonH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[faceButton][moreButton(==faceButton)]|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(faceButton,moreButton)]; [self addConstraints:buttonH]; //新增垂直約束 NSArray *button1V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[faceButton]|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(faceButton)]; [self addConstraints:button1V]; NSArray *button2V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[moreButton]|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(moreButton)]; [self addConstraints:button2V]; } return self; } //接受傳入的回撥 -(void) setToolIndex:(ToolIndex)toolBlock { self.myBlock = toolBlock; } //點選表情按鈕要回撥的方法 -(void) tapFaceButton: (id) sender { self.myBlock(1); } //點選more要回撥的方法 -(void) tapMoreButton: (id) sender { self.myBlock(2); } @end |
程式碼說明:
主要是對block回撥的應用和給相應的元件新增相應的約束
4.MoreView元件的封裝程式碼就不往上貼啦,和上面的類似,下面是呼叫MoreView元件的執行效果,有興趣的讀者請自行編寫,以上就是檢視部分的程式碼了
二. Mode部分的內容:
1.先定義我們要使用的資料模型,資料模型如下,time是使用表情的時間,用於排序。
2.下面編寫我們的ImageModelClass類,裡面封裝了我們運算元據要用的方法
ImageModelClass.h的程式碼如下,主要是預留的對外的介面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// // ImageModelClass.h // MyKeyBoard // // Created by 青玉伏案 on 14-9-16. // Copyright (c) 2014年 Mrli. All rights reserved. // #import <Foundation/Foundation.h> #import <CoreData/CoreData.h> #import "HistoryImage.h" @interface ImageModelClass : NSObject //儲存資料 -(void)save:(NSData *) image ImageText:(NSString *) imageText; //查詢所有的圖片 -(NSArray *) queryAll; @end |
ImageModelClass.m的程式碼如下,主要是用CoreData對sqlite的操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
// // ImageModelClass.m // MyKeyBoard // // Created by 青玉伏案 on 14-9-16. // Copyright (c) 2014年 Mrli. All rights reserved. // #import "ImageModelClass.h" @interface ImageModelClass () @property (nonatomic, strong) NSManagedObjectContext *manager; @end @implementation ImageModelClass - (instancetype)init { self = [super init]; if (self) { //通過上下文獲取manager UIApplication *application = [UIApplication sharedApplication]; id delegate = application.delegate; self.manager = [delegate managedObjectContext]; } return self; } -(void)save:(NSData *)image ImageText:(NSString *)imageText { if (image != nil) { NSArray *result = [self search:imageText]; HistoryImage *myImage; if (result.count == 0) { myImage = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([HistoryImage class]) inManagedObjectContext:self.manager]; myImage.imageText = imageText; myImage.headerImage = image; myImage.time = [NSDate date]; } else { myImage = result[0]; myImage.time = [NSDate date]; } //儲存實體 NSError *error = nil; if (![self.manager save:&error]) { NSLog(@"儲存出錯%@", [error localizedDescription]); } } } //查詢 -(NSArray *)search:(NSString *) image { NSArray *result; //新建查詢條件 NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:NSStringFromClass([HistoryImage class])]; //新增謂詞 NSPredicate *predicate = [NSPredicate predicateWithFormat:@"imageText=%@",image]; //把謂詞給request [fetchRequest setPredicate:predicate]; //執行查詢 NSError *error = nil; result = [self.manager executeFetchRequest:fetchRequest error:&error]; if (error) { NSLog(@"查詢錯誤:%@", [error localizedDescription]); } return result; } //查詢所有的 -(NSArray *) queryAll { //新建查詢條件 NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:NSStringFromClass([HistoryImage class])]; //新增排序規則 //定義排序規則 NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"time" ascending:NO]; //新增排序規則 [fetchRequest setSortDescriptors:@[sortDescriptor]]; //執行查詢 NSError *error = nil; NSArray *result = [self.manager executeFetchRequest:fetchRequest error:&error]; if (error) { NSLog(@"查詢錯誤:%@", [error localizedDescription]); } return result; } @end |
程式碼說明:
1.儲存圖片時先查詢圖片是否存在,如果存在則更新時間,如果不存在則插入資料(寫到這感覺想在用Hibernate寫東西)。
三.Controller部分,把上面的元件進行組裝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
1.MainViewController.m中的延展部分的程式碼如下: @interface MainViewController () //自定義元件 @property (nonatomic, strong) ToolView *toolView; @property (nonatomic, strong) FunctionView *functionView; @property (nonatomic, strong) MoreView *moreView; //系統元件 @property (strong, nonatomic) IBOutlet UITextView *myTextView; @property (strong, nonatomic) NSDictionary *keyBoardDic; @property (strong, nonatomic) IBOutlet UIImageView *imageView; @property (strong, nonatomic) NSString *sendString; //資料model @property (strong, nonatomic) ImageModelClass *imageMode; @property (strong, nonatomic)HistoryImage *tempImage; @end |
2.在viewDidLoad中進行元件的初始化和實現元件的Block回撥,程式碼如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
- (void)viewDidLoad { [super viewDidLoad]; //從sqlite中讀取資料 self.imageMode = [[ImageModelClass alloc] init]; //例項化FunctionView self.functionView = [[FunctionView alloc] initWithFrame:CGRectMake(0, 0, 320, 216)]; self.functionView.backgroundColor = [UIColor blackColor]; //設定資源載入的檔名 self.functionView.plistFileName = @"emoticons"; __weak __block MainViewController *copy_self = self; //獲取圖片並顯示 [self.functionView setFunctionBlock:^(UIImage *image, NSString *imageText) { NSString *str = [NSString stringWithFormat:@"%@%@",copy_self.myTextView.text, imageText]; copy_self.myTextView.text = str; copy_self.imageView.image = image; //把使用過的圖片存入sqlite NSData *imageData = UIImagePNGRepresentation(image); [copy_self.imageMode save:imageData ImageText:imageText]; }]; //例項化MoreView self.moreView = [[MoreView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)]; self.moreView.backgroundColor = [UIColor blackColor]; [self.moreView setMoreBlock:^(NSInteger index) { NSLog(@"MoreIndex = %d",index); }]; //進行ToolView的例項化 self.toolView = [[ToolView alloc] initWithFrame:CGRectZero]; self.toolView.backgroundColor = [UIColor blackColor]; [self.view addSubview:self.toolView]; //給ToolView新增約束 //開啟自動佈局 self.toolView.translatesAutoresizingMaskIntoConstraints = NO; //水平約束 NSArray *toolHConstraint = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_toolView]|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(_toolView)]; [self.view addConstraints:toolHConstraint]; //垂直約束 NSArray *toolVConstraint = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[_toolView(44)]|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(_toolView)]; [self.view addConstraints:toolVConstraint]; //回撥toolView中的方法 [self.toolView setToolIndex:^(NSInteger index) { NSLog(@"%d", index); switch (index) { case 1: [copy_self changeKeyboardToFunction]; break; case 2: [copy_self changeKeyboardToMore]; break; default: break; } }]; //當鍵盤出來的時候通過通知來獲取鍵盤的資訊 //註冊為鍵盤的監聽著 NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(keyNotification:) name:UIKeyboardWillChangeFrameNotification object:nil]; //給鍵盤新增dan //TextView的鍵盤定製回收按鈕 UIToolbar * toolBar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 30)]; UIBarButtonItem * item1 = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(tapDone:)]; UIBarButtonItem * item2 = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; UIBarButtonItem * item3 = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; toolBar.items = @[item2,item1,item3]; self.myTextView.inputAccessoryView =toolBar; } |
3.當橫豎螢幕切換時設定自定義鍵盤的高度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { //縱屏 if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) { CGRect frame = self.functionView.frame; frame.size.height = 216; self.functionView.frame = frame; self.moreView.frame = frame; } //橫屏 if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) { CGRect frame = self.functionView.frame; frame.size.height = 150; self.functionView.frame = frame; self.moreView.frame = frame; } } |
4.當鍵盤出來的時候,改變toolView的位置,通過鍵盤的通知來實現。當橫屏的時候鍵盤的座標系和我們當前的Frame的座標系不一樣所以當橫屏時得做一座標系的轉換,程式碼如下;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
//當鍵盤出來的時候改變toolView的位置(接到鍵盤出來的通知要做的方法) -(void) keyNotification : (NSNotification *) notification { NSLog(@"%@", notification.userInfo); self.keyBoardDic = notification.userInfo; //獲取鍵盤移動後的座標點的座標點 CGRect rect = [self.keyBoardDic[@"UIKeyboardFrameEndUserInfoKey"] CGRectValue]; //把鍵盤的座標系改成當前我們window的座標系 CGRect r1 = [self.view convertRect:rect fromView:self.view.window]; [UIView animateWithDuration:[self.keyBoardDic[UIKeyboardAnimationDurationUserInfoKey] floatValue] animations:^{ //動畫曲線 [UIView setAnimationCurve:[self.keyBoardDic[UIKeyboardAnimationCurveUserInfoKey] doubleValue]]; CGRect frame = self.toolView.frame; frame.origin.y = r1.origin.y - frame.size.height; //根據鍵盤的高度來改變toolView的高度 self.toolView.frame = frame; }]; } |
5.系統鍵盤和自定義鍵盤切換的程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
//切換鍵盤的方法 -(void) changeKeyboardToFunction { if ([self.myTextView.inputView isEqual:self.functionView]) { self.myTextView.inputView = nil; [self.myTextView reloadInputViews]; } else { self.myTextView.inputView = self.functionView; [self.myTextView reloadInputViews]; } if (![self.myTextView isFirstResponder]) { [self.myTextView becomeFirstResponder]; } } |
以上就是上面展示效果的核心程式碼了,在做的時候感覺難點在於如何進行螢幕適配,尤其是當螢幕橫過來的時候鍵盤的座標系和我們frame的座標系不同,得做一個轉換。發表部落格的目的是想起到拋磚引玉的作用,有好的東西希望大家相互交流一下。筆者水平有限難免有偏頗之處,歡迎批評指正。
Demo地址:https://github.com/lizelu/WeChat
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!