iOS組件封裝與自動(dòng)布局自定義表情鍵盤(pán)
下面的東西是編寫(xiě)自定義的表情鍵盤(pán),話不多說(shuō),開(kāi)門見(jiàn)山吧!下面主要用到的知識(shí)有MVC, iOS開(kāi)發(fā)中的自動(dòng)布局,自定義組件的封裝與使用,Block回調(diào),CoreData的使用。有的小伙伴可能會(huì)問(wèn)寫(xiě)一個(gè)自定義表情鍵盤(pán)腫么這么麻煩?下面 將會(huì)介紹我們?nèi)绾斡蒙厦嫣岬降臇|西來(lái)定義我們的表情鍵盤(pán)的。下面的內(nèi)容會(huì)比較多,這篇文章還是比較有料的。
還是那句話寫(xiě)技術(shù)博客是少不了代碼的,下面會(huì)結(jié)合代碼來(lái)回顧一下iOS的知識(shí),本篇博文中用到的知識(shí)點(diǎn)在前面的博客中都能找到相應(yīng)的內(nèi)容,本篇 算是一個(gè)小小的功能整合。先來(lái)張圖看一下本app的目錄結(jié)構(gòu)。我是根據(jù)自己對(duì)MVC的理解來(lái)構(gòu)建的目錄結(jié)構(gòu),希望起到拋磚引玉的作用,有好的解決方案歡迎 評(píng)論或者留言指出。Face文件中存放的時(shí)我們的表情圖片,Model文件封裝的是從sqlite中讀取歷史頭像的組件,View文件中封裝的時(shí)我們自定義的組件,也就是自定義鍵盤(pán)相關(guān)的視圖,Controller負(fù)責(zé)將我們的各個(gè)組件組裝到一起完成我們想要的功能。下面會(huì)一一介紹。
上面是文件的組織結(jié)構(gòu),下面為了更為直觀的了解我們想要的效果,下面先看幾張截圖,來(lái)直觀的感受一下運(yùn)行效果,上面是豎屏的顯示效果,下面是橫 屏的顯示效果。因?yàn)樵诜庋b自定義鍵盤(pán)中用到了自動(dòng)布局所以橫屏顯示或者在更大的屏幕上顯示是沒(méi)問(wèn)題的,常用表情是用戶用過(guò)的表情,然后存在Sqlite 中,顯示時(shí)并按時(shí)間降序排列。more是用來(lái)擴(kuò)展功能用的接口。話不多說(shuō),來(lái)的代碼才是實(shí)在的。
一.View(自定義視圖)
View文件夾下存放的時(shí)我們自定義的視圖組件,因?yàn)槭亲远x的組件所以storyboard我們就用不了啦,所有的代碼都必須手寫(xiě),這樣 才能保證組件使用的靈活性和減少各個(gè)組件之間的耦合性,更利于團(tuán)隊(duì)之間的合作。在封裝組件時(shí)要預(yù)留好外界可能使用到的接口,和返回該返回的數(shù)據(jù)。好啦,廢話少說(shuō),來(lái)點(diǎn)干貨吧!
1、FaceView組件的封裝:FaceView即負(fù)責(zé)顯示一個(gè)個(gè)的頭像。在使用該組件時(shí)要傳入要顯示的圖片和圖片對(duì)應(yīng)的文字(如【哈 哈】),當(dāng)點(diǎn)擊圖片的時(shí)候,會(huì)通過(guò)block回調(diào)的形式把該圖片的image以及圖片文字返回到使用的組件中去,下面是關(guān)鍵代碼:
FaceView.h中的代碼如下(下面代碼是定義啦相應(yīng)的Block類型和對(duì)外的接口):
#import //聲明表情對(duì)應(yīng)的block,用于把點(diǎn)擊的表情的圖片和圖片信息傳到上層視圖 typedef void (^FaceBlock) (UIImage *image, NSString *imageText); @interface FaceView : UIView //圖片對(duì)應(yīng)的文字 @property (nonatomic, strong) NSString *imageText; //表情圖片 @property (nonatomic, strong) UIImage *headerImage; //設(shè)置block回調(diào) -(void)setFaceBlock:(FaceBlock)block; //設(shè)置圖片,文字 -(void)setImage:(UIImage *) image ImageText:(NSString *) text; @end
FaceView.m中的代碼如下
// 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]; //把圖片存儲(chǔ)起來(lái) self.headerImage = image; self.imageText = text; } //點(diǎn)擊時(shí)回調(diào) -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint point = [touch locationInView:self]; //判斷觸摸的結(jié)束點(diǎn)是否在圖片中 if (CGRectContainsPoint(self.bounds, point)) { //回調(diào),把該頭像的信息傳到相應(yīng)的controller中 self.block(self.headerImage, self.imageText); } } @end
代碼說(shuō)明:
主要就是block回調(diào)的使用,就是封裝了一個(gè)自定義的button
2、FunctionView組件的封裝,F(xiàn)unctionView就是使用FaceView組件和ScrollView組件把表情加載進(jìn)來(lái),在實(shí)例化FunctionView組件時(shí),我們用到了自動(dòng)布局來(lái)設(shè)置ScrollView和下面的Button.
FunctionView.h的代碼如下,在.h中留有組件的接口和回調(diào)用的Block, plistFileName用于加載我們的資源文件時(shí)使用。
// FunctionView.h // MyKeyBoard // // Created by 青玉伏案 on 14-9-16. // Copyright (c) 2014年 Mrli. All rights reserved. // #import //定義對(duì)應(yīng)的block類型,用于數(shù)據(jù)的交互 typedef void (^FunctionBlock) (UIImage *image, NSString *imageText); @interface FunctionView : UIView //資源文件名 @property (nonatomic, strong) NSString *plistFileName; //接受block塊 -(void)setFunctionBlock:(FunctionBlock) block; @end
FunctionView.m中的代碼如下,常用表情是在sqlite中獲取的,而全部表情是通過(guò)plist文件的信息在Face文件中加載的:
// 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; //暫存表情組件回調(diào)的表情和表情文字 @property (strong, nonatomic) UIImage *headerImage; @property (strong, nonatomic) NSString *imageText; //display我們的表情圖片 @property (strong, nonatomic) UIScrollView *headerScrollView; //定義數(shù)據(jù)模型用于獲取歷史表情 @property (strong, nonatomic) ImageModelClass *imageModel; @end @implementation FunctionView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { //實(shí)例化數(shù)據(jù)模型 self.imageModel =[[ImageModelClass alloc] init]; //實(shí)例化下面的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]; //實(shí)例化常用表情按鈕 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]; //默認(rèn)顯示表情圖片 [self tapButton1:nil]; } return self; } //接受回調(diào) -(void)setFunctionBlock:(FunctionBlock)block { self.block = block; } //點(diǎn)擊全部表情按鈕回調(diào)方法 -(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(@"訪問(wèn)的plist文件不存在"); } else { //調(diào)用headers方法顯示表情 [self header:headers]; } } //點(diǎn)擊歷史表情的回調(diào)方法 -(void) tapButton2: (id) sender { //從數(shù)據(jù)庫(kù)中查詢所有的圖片 NSArray *imageData = [self.imageModel queryAll]; //解析請(qǐng)求到的數(shù)據(jù) NSMutableArray *headers = [NSMutableArray arrayWithCapacity:imageData.count]; //數(shù)據(jù)實(shí)體,相當(dāng)于javaBean的東西 HistoryImage *tempData; for (int i = 0; i < imageData.count; i ++) { tempData = imageData[i]; //解析數(shù)據(jù),轉(zhuǎn)換成函數(shù)headers要用的數(shù)據(jù)格式 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]; } //負(fù)責(zé)把查出來(lái)的圖片顯示 -(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; //根據(jù)圖片量來(lái)計(jì)算scrollView的Contain的寬度 CGFloat width = (headers.count/(scrollHeight/30))*30; self.headerScrollView.contentSize = CGSizeMake(width, scrollHeight); self.headerScrollView.pagingEnabled = YES; //圖片坐標(biāo) 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"]; //計(jì)算圖片位置 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的回調(diào),當(dāng)face點(diǎn)擊時(shí)獲取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
代碼說(shuō)明:
1、主要是通過(guò)對(duì)資源文件或者對(duì)從數(shù)據(jù)庫(kù)中查詢的資源進(jìn)行遍歷然后添加到ScrollView中
2.為了適應(yīng)不同的屏幕給相應(yīng)的組件添加了約束
3.ToolView組件的封裝: ToolView就是在主屏幕上下面的類似于TabBar的東西,當(dāng)鍵盤(pán)出來(lái)的時(shí)候,ToolView會(huì)運(yùn)動(dòng)到鍵盤(pán)上面的位置。為了使用不同的屏幕,也需要用自動(dòng)布局來(lái)實(shí)現(xiàn)。
ToolView.h的代碼如下:預(yù)留組件接口和聲明block類型
// ToolView.h // MyKeyBoard // // Created by 青玉伏案 on 14-9-16. // Copyright (c) 2014年 Mrli. All rights reserved. // /***************** 封裝下面的工具條組件 *****************/ #import //定義block塊變量類型,用于回調(diào),把本View上的按鈕的index傳到Controller中 typedef void (^ToolIndex) (NSInteger index); @interface ToolView : UIView //塊變量類型的setter方法 -(void)setToolIndex:(ToolIndex) toolBlock; @end ToolView.m的代碼實(shí)現(xiàn): // ToolView.m // MyKeyBoard // // Created by 青玉伏案 on 14-9-16. // Copyright (c) 2014年 Mrli. All rights reserved. // #import "ToolView.h" @interface ToolView () //定義ToolIndex類型的block,用于接受外界傳過(guò)來(lái)的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]; //給我們的按鈕添加約束來(lái)讓按鈕來(lái)占滿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; } //接受傳入的回調(diào) -(void) setToolIndex:(ToolIndex)toolBlock { self.myBlock = toolBlock; } //點(diǎn)擊表情按鈕要回調(diào)的方法 -(void) tapFaceButton: (id) sender { self.myBlock(1); } //點(diǎn)擊more要回調(diào)的方法 -(void) tapMoreButton: (id) sender { self.myBlock(2); } @end
代碼說(shuō)明:
主要是對(duì)block回調(diào)的應(yīng)用和給相應(yīng)的組件添加相應(yīng)的約束。
4.MoreView組件的封裝代碼就不往上貼啦,和上面的類似,下面是調(diào)用MoreView組件的運(yùn)行效果,有興趣的讀者請(qǐng)自行編寫(xiě),以上就是視圖部分的代碼了
二. Mode部分的內(nèi)容
1.先定義我們要使用的數(shù)據(jù)模型,數(shù)據(jù)模型如下,time是使用表情的時(shí)間,用于排序。
2.下面編寫(xiě)我們的ImageModelClass類,里面封裝了我們操作數(shù)據(jù)要用的方法
ImageModelClass.h的代碼如下,主要是預(yù)留的對(duì)外的接口:
// // ImageModelClass.h // MyKeyBoard // // Created by 青玉伏案 on 14-9-16. // Copyright (c) 2014年 Mrli. All rights reserved. // #import #import #import "HistoryImage.h" @interface ImageModelClass : NSObject //保存數(shù)據(jù) -(void)save:(NSData *) image ImageText:(NSString *) imageText; //查詢所有的圖片 -(NSArray *) queryAll; @end
ImageModelClass.m的代碼如下,主要是用CoreData對(duì)sqlite的操作:
// 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) { //通過(guò)上下文獲取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]; } //存儲(chǔ)實(shí)體 NSError *error = nil; if (![self.manager save:&error]) { NSLog(@"保存出錯(cuò)%@", [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]; //執(zhí)行查詢 NSError *error = nil; result = [self.manager executeFetchRequest:fetchRequest error:&error]; if (error) { NSLog(@"查詢錯(cuò)誤:%@", [error localizedDescription]); } return result; } //查詢所有的 -(NSArray *) queryAll { //新建查詢條件 NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:NSStringFromClass([HistoryImage class])]; //添加排序規(guī)則 //定義排序規(guī)則 NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"time" ascending:NO]; //添加排序規(guī)則 [fetchRequest setSortDescriptors:@[sortDescriptor]]; //執(zhí)行查詢 NSError *error = nil; NSArray *result = [self.manager executeFetchRequest:fetchRequest error:&error]; if (error) { NSLog(@"查詢錯(cuò)誤:%@", [error localizedDescription]); } return result; } @end
代碼說(shuō)明:
1.保存圖片時(shí)先查找圖片是否存在,如果存在則更新時(shí)間,如果不存在則插入數(shù)據(jù)(寫(xiě)到這感覺(jué)想在用Hibernate寫(xiě)東西)。
三.Controller部分,把上面的組件進(jìn)行組裝
1.MainViewController.m中的延展部分的代碼如下:
@interface MainViewController () //自定義組件 @property (nonatomic, strong) ToolView *toolView; @property (nonatomic, strong) FunctionView *functionView; @property (nonatomic, strong) MoreView *moreView; //系統(tǒng)組件 @property (strong, nonatomic) IBOutlet UITextView *myTextView; @property (strong, nonatomic) NSDictionary *keyBoardDic; @property (strong, nonatomic) IBOutlet UIImageView *imageView; @property (strong, nonatomic) NSString *sendString; //數(shù)據(jù)model @property (strong, nonatomic) ImageModelClass *imageMode; @property (strong, nonatomic)HistoryImage *tempImage; @end
2.在viewDidLoad中進(jìn)行組件的初始化和實(shí)現(xiàn)組件的Block回調(diào),代碼如下
- (void)viewDidLoad { [super viewDidLoad]; //從sqlite中讀取數(shù)據(jù) self.imageMode = [[ImageModelClass alloc] init]; //實(shí)例化FunctionView self.functionView = [[FunctionView alloc] initWithFrame:CGRectMake(0, 0, 320, 216)]; self.functionView.backgroundColor = [UIColor blackColor]; //設(shè)置資源加載的文件名 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; //把使用過(guò)的圖片存入sqlite NSData *imageData = UIImagePNGRepresentation(image); [copy_self.imageMode save:imageData ImageText:imageText]; }]; //實(shí)例化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); }]; //進(jìn)行ToolView的實(shí)例化 self.toolView = [[ToolView alloc] initWithFrame:CGRectZero]; self.toolView.backgroundColor = [UIColor blackColor]; [self.view addSubview:self.toolView]; //給ToolView添加約束 //開(kāi)啟自動(dòng)布局 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]; //回調(diào)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; } }]; //當(dāng)鍵盤(pán)出來(lái)的時(shí)候通過(guò)通知來(lái)獲取鍵盤(pán)的信息 //注冊(cè)為鍵盤(pán)的監(jiān)聽(tīng)著 NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(keyNotification:) name:UIKeyboardWillChangeFrameNotification object:nil]; //給鍵盤(pán)添加dan //TextView的鍵盤(pán)定制回收按鈕 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.當(dāng)橫豎屏幕切換時(shí)設(shè)置自定義鍵盤(pán)的高度
-(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.當(dāng)鍵盤(pán)出來(lái)的時(shí)候,改變toolView的位置,通過(guò)鍵盤(pán)的通知來(lái)實(shí)現(xiàn)。當(dāng)橫屏的時(shí)候鍵盤(pán)的坐標(biāo)系和我們當(dāng)前的Frame的坐標(biāo)系不一樣所以當(dāng)橫屏?xí)r得做一坐標(biāo)系的轉(zhuǎn)換,代碼如下:
//當(dāng)鍵盤(pán)出來(lái)的時(shí)候改變toolView的位置(接到鍵盤(pán)出來(lái)的通知要做的方法) -(void) keyNotification : (NSNotification *) notification { NSLog(@"%@", notification.userInfo); self.keyBoardDic = notification.userInfo; //獲取鍵盤(pán)移動(dòng)后的坐標(biāo)點(diǎn)的坐標(biāo)點(diǎn) CGRect rect = [self.keyBoardDic[@"UIKeyboardFrameEndUserInfoKey"] CGRectValue]; //把鍵盤(pán)的坐標(biāo)系改成當(dāng)前我們window的坐標(biāo)系 CGRect r1 = [self.view convertRect:rect fromView:self.view.window]; [UIView animateWithDuration:[self.keyBoardDic[UIKeyboardAnimationDurationUserInfoKey] floatValue] animations:^{ //動(dòng)畫(huà)曲線 [UIView setAnimationCurve:[self.keyBoardDic[UIKeyboardAnimationCurveUserInfoKey] doubleValue]]; CGRect frame = self.toolView.frame; frame.origin.y = r1.origin.y - frame.size.height; //根據(jù)鍵盤(pán)的高度來(lái)改變toolView的高度 self.toolView.frame = frame; }]; }
5.系統(tǒng)鍵盤(pán)和自定義鍵盤(pán)切換的代碼如下:
//切換鍵盤(pán)的方法 -(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]; } }
以上就是上面展示效果的核心代碼了,在做的時(shí)候感覺(jué)難點(diǎn)在于如何進(jìn)行屏幕適配,尤其是當(dāng)屏幕橫過(guò)來(lái)的時(shí)候鍵盤(pán)的坐標(biāo)系和我們frame的坐標(biāo)系不同,得做 一個(gè)轉(zhuǎn)換。發(fā)表文章的目的是想起到拋磚引玉的左右,有好的東西希望大家相互交流一下。
相關(guān)文章
詳解iOS應(yīng)用中自定義UIBarButtonItem導(dǎo)航按鈕的創(chuàng)建方法
這篇文章主要介紹了iOS應(yīng)用中自定義UIBarButtonItem導(dǎo)航按鈕的創(chuàng)建方法,文中舉了一個(gè)自定義圖片的UIBarButtonItem實(shí)例,比較具有代表性,需要的朋友可以參考下2016-04-04iOS使用音頻處理框架The Amazing Audio Engine實(shí)現(xiàn)音頻錄制播放
這篇文章主要為大家詳細(xì)介紹了iOS使用音頻處理框架The Amazing Audio Engine實(shí)現(xiàn)音頻錄制播放,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-04-04iOS瀑布流的簡(jiǎn)單實(shí)現(xiàn)(Swift)
這篇文章主要介紹了iOS瀑布流的簡(jiǎn)單實(shí)現(xiàn),說(shuō)到瀑布流, 或許大家都不陌生, 瀑布流的實(shí)現(xiàn)也有很多種! 本文使用兩種方法介紹,有興趣的可以了解一下。2016-11-11ios UITableView實(shí)現(xiàn)無(wú)數(shù)據(jù)加載占位圖片
這篇文章主要介紹了ios UITableView實(shí)現(xiàn)無(wú)數(shù)據(jù)占位圖片,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08iOS框架AVFoundation實(shí)現(xiàn)相機(jī)拍照、錄制視頻
這篇文章主要為大家詳細(xì)介紹了iOS框架AVFoundation實(shí)現(xiàn)相機(jī)拍照、錄制視頻功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05