今天准備寫個博客帶大家一步一步封裝一個聊天鍵盤,先上git地址(https://github.com/GitBaoChao/BCKeyboard.git,記得下載了,給我點個star啊)
第二篇地址(http://www.cnblogs.com/bcblogs/p/4707512.html),希望大家認真去看哦,不懂的可以在評論里問
眾所周知,一個聊天鍵盤,肯定要有表情,發送圖片啊,語音啊,視頻什么的,我封裝的就只有表情(是emoji),其他幾個擴展的,放在一個view里,等以后在去添加功能
好吧,我們開始,首先要思考封裝一個這樣的聊天鍵盤,我們需要什么,肯定需要一個表情按鈕,UItextView,還有一個擴展的view,而UITextView可能需要有占位文字,所以我們首先自己定制有占位文字的UITextView
繼承UITextView創建一個自定義的UITextView,我的叫BCTextView
BCTextView.h文件
#import <UIKit/UIKit.h> @interface BCTextView : UITextView @property (nonatomic, retain) NSString *placeholder; @property (nonatomic, retain) UIColor *placeholderColor; @end
BCTextView.m文件
#import "BCTextView.h" @interface BCTextView () @end @implementation BCTextView - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil]; self.autoresizesSubviews = NO; //默認字和顏色 self.placeholder = @""; self.placeholderColor = [UIColor lightGrayColor]; } return self; } - (void)drawRect:(CGRect)rect { //內容為空時才繪制placeholder if ([self.text isEqualToString:@""]) { CGRect placeholderRect; placeholderRect.origin.y = 8; placeholderRect.size.height = CGRectGetHeight(self.frame)-8; placeholderRect.origin.x = 5; placeholderRect.size.width = CGRectGetWidth(self.frame)-5; [self.placeholderColor set]; [self.placeholder drawInRect:placeholderRect withFont:self.font lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentLeft]; } } - (void)textChanged:(NSNotification *)not { [self setNeedsDisplay]; } - (void)setText:(NSString *)text { [super setText:text]; [self setNeedsDisplay]; }
准備工作完成,現在我們來自定義鍵盤,繼承UIView新建一個類
我們一步一步的來,我們的布局是左邊表情按鈕,中間textView,右邊擴展按鈕
先給大家看看宏定義吧
#define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width) #define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height) #define kBCTextViewHeight 36 /**< 底部textView的高度 */ #define kHorizontalPadding 8 /**< 橫向間隔 */ #define kVerticalPadding 5 /**< 縱向間隔 */
Key.m文件
#import "BCKeyBoard.h" #define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width) #define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height) #define kBCTextViewHeight 36 /**< 底部textView的高度 */ #define kHorizontalPadding 8 /**< 橫向間隔 */ #define kVerticalPadding 5 /**< 縱向間隔 */ @interface BCKeyBoard() <UITextViewDelegate> @property (nonatomic,strong)UIButton *faceBtn; @property (nonatomic,strong)UIButton *moreBtn; @property (nonatomic,strong)BCTextView *textView; @property (nonatomic,strong)UIImageView *backgroundImageView; @end @implementation BCKeyBoard - (instancetype)initWithFrame:(CGRect)frame { if (frame.size.height < (kVerticalPadding * 2 + kBCTextViewHeight)) { frame.size.height = kVerticalPadding * 2 + kBCTextViewHeight; } self = [super initWithFrame:frame]; if (self) { [self createUI]; } return self; } - (void)setFrame:(CGRect)frame { if (frame.size.height < (kVerticalPadding * 2 + kBCTextViewHeight)) { frame.size.height = kVerticalPadding * 2 + kBCTextViewHeight; } [super setFrame:frame]; } - (void)createUI{ self.backgroundImageView = [[UIImageView alloc] initWithFrame:self.bounds]; self.backgroundImageView.userInteractionEnabled = YES; self.backgroundImageView.image = [[UIImage imageNamed:@"messageToolbarBg"] stretchableImageWithLeftCapWidth:0.5 topCapHeight:10]; //表情按鈕 self.faceBtn = [UIButton buttonWithType:UIButtonTypeCustom]; self.faceBtn.frame = CGRectMake(kHorizontalPadding,kHorizontalPadding, 30, 30); [self.faceBtn addTarget:self action:@selector(willShowFaceView:) forControlEvents:UIControlEventTouchUpInside]; [self.faceBtn setBackgroundImage:[UIImage imageNamed:@"chatBar_face"] forState:UIControlStateNormal]; [self.faceBtn setBackgroundImage:[UIImage imageNamed:@"chatBar_keyboard"] forState:UIControlStateSelected]; [self addSubview:self.faceBtn]; //文本 self.textView = [[BCTextView alloc] initWithFrame:CGRectMake(CGRectGetMaxX(self.faceBtn.frame)+kHorizontalPadding, kHorizontalPadding, self.bounds.size.width - 4*kHorizontalPadding - 30*2, 30)]; self.textView.placeholderColor = [UIColor lightGrayColor]; self.textView.returnKeyType = UIReturnKeySend; self.textView.scrollEnabled = NO; self.textView.backgroundColor = [UIColor clearColor]; self.textView.layer.borderColor = [UIColor colorWithWhite:0.8f alpha:1.0f].CGColor; self.textView.layer.borderWidth = 0.65f; self.textView.layer.cornerRadius = 6.0f; self.textView.delegate = self; //更多按鈕 self.moreBtn = [UIButton buttonWithType:UIButtonTypeCustom]; self.moreBtn.frame = CGRectMake(CGRectGetMaxX(self.textView.frame)+kHorizontalPadding,kHorizontalPadding,30,30); [self.moreBtn addTarget:self action:@selector(willShowMoreView:) forControlEvents:UIControlEventTouchUpInside]; [self.moreBtn setBackgroundImage:[UIImage imageNamed:@"chatBar_more"] forState:UIControlStateNormal]; [self.moreBtn setBackgroundImage:[UIImage imageNamed:@"chatBar_keyboard"] forState:UIControlStateSelected]; [self addSubview:self.backgroundImageView]; [self.backgroundImageView addSubview:self.textView]; [self.backgroundImageView addSubview:self.faceBtn]; [self.backgroundImageView addSubview:self.moreBtn]; } - (void)willShowFaceView:(UIButton *)btn{ } - (void)willShowMoreView:(UIButton *)btn{ }
在ViewController.m中
#import "ViewController.h" #import "BCKeyBoard.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; BCKeyBoard *bc = [[BCKeyBoard alloc] initWithFrame:CGRectMake(0, [UIScreen mainScreen].bounds.size.height - 46, [UIScreen mainScreen].bounds.size.width,46)]; bc.backgroundColor = [UIColor clearColor]; [self.view addSubview:bc]; }
運行效果
我們還要根據鍵盤彈起的高度,將自定義的view隨之彈起,用的是通知,根據鍵盤彈起的高度,去改變自定義view的高度,使之始終在鍵盤的上面
#import "BCKeyBoard.h" #define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width) #define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height) #define kBCTextViewHeight 36 /**< 底部textView的高度 */ #define kHorizontalPadding 8 /**< 橫向間隔 */ #define kVerticalPadding 5 /**< 縱向間隔 */ @interface BCKeyBoard() <UITextViewDelegate> @property (nonatomic,strong)UIButton *faceBtn; @property (nonatomic,strong)UIButton *moreBtn; @property (nonatomic,strong)BCTextView *textView; @property (nonatomic,strong)UIImageView *backgroundImageView; @end @implementation BCKeyBoard - (instancetype)initWithFrame:(CGRect)frame { if (frame.size.height < (kVerticalPadding * 2 + kBCTextViewHeight)) { frame.size.height = kVerticalPadding * 2 + kBCTextViewHeight; } self = [super initWithFrame:frame]; if (self) { [self createUI]; } return self; } - (void)setFrame:(CGRect)frame { if (frame.size.height < (kVerticalPadding * 2 + kBCTextViewHeight)) { frame.size.height = kVerticalPadding * 2 + kBCTextViewHeight; } [super setFrame:frame]; } - (void)createUI{ //鍵盤高度改變是調用 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil]; self.backgroundImageView = [[UIImageView alloc] initWithFrame:self.bounds]; self.backgroundImageView.userInteractionEnabled = YES; self.backgroundImageView.image = [[UIImage imageNamed:@"messageToolbarBg"] stretchableImageWithLeftCapWidth:0.5 topCapHeight:10]; //表情按鈕 self.faceBtn = [UIButton buttonWithType:UIButtonTypeCustom]; self.faceBtn.frame = CGRectMake(kHorizontalPadding,kHorizontalPadding, 30, 30); [self.faceBtn addTarget:self action:@selector(willShowFaceView:) forControlEvents:UIControlEventTouchUpInside]; [self.faceBtn setBackgroundImage:[UIImage imageNamed:@"chatBar_face"] forState:UIControlStateNormal]; [self.faceBtn setBackgroundImage:[UIImage imageNamed:@"chatBar_keyboard"] forState:UIControlStateSelected]; [self addSubview:self.faceBtn]; //文本 self.textView = [[BCTextView alloc] initWithFrame:CGRectMake(CGRectGetMaxX(self.faceBtn.frame)+kHorizontalPadding, kHorizontalPadding, self.bounds.size.width - 4*kHorizontalPadding - 30*2, 30)]; self.textView.placeholderColor = [UIColor lightGrayColor]; self.textView.returnKeyType = UIReturnKeySend; self.textView.scrollEnabled = NO; self.textView.backgroundColor = [UIColor clearColor]; self.textView.layer.borderColor = [UIColor colorWithWhite:0.8f alpha:1.0f].CGColor; self.textView.layer.borderWidth = 0.65f; self.textView.layer.cornerRadius = 6.0f; self.textView.delegate = self; //更多按鈕 self.moreBtn = [UIButton buttonWithType:UIButtonTypeCustom]; self.moreBtn.frame = CGRectMake(CGRectGetMaxX(self.textView.frame)+kHorizontalPadding,kHorizontalPadding,30,30); [self.moreBtn addTarget:self action:@selector(willShowMoreView:) forControlEvents:UIControlEventTouchUpInside]; [self.moreBtn setBackgroundImage:[UIImage imageNamed:@"chatBar_more"] forState:UIControlStateNormal]; [self.moreBtn setBackgroundImage:[UIImage imageNamed:@"chatBar_keyboard"] forState:UIControlStateSelected]; [self addSubview:self.backgroundImageView]; [self.backgroundImageView addSubview:self.textView]; [self.backgroundImageView addSubview:self.faceBtn]; [self.backgroundImageView addSubview:self.moreBtn]; } - (void)keyboardWillChangeFrame:(NSNotification *)notification{ NSDictionary *userInfo = notification.userInfo; CGRect endFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; CGFloat duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]; //動畫 void(^animations)() = ^{ CGRect frame = self.frame; frame.origin.y = endFrame.origin.y - self.bounds.size.height; self.frame = frame; }; void(^completion)(BOOL) = ^(BOOL finished){ }; [UIView animateWithDuration:duration delay:0.0f options:(curve << 16 | UIViewAnimationOptionBeginFromCurrentState) animations:animations completion:completion]; } - (void)willShowFaceView:(UIButton *)btn{ } - (void)willShowMoreView:(UIButton *)btn{ } @end
運行效果
是不是很棒.....,接下來,我們寫表情按鈕點擊事件,表情按鈕點擊的時候彈出的肯定是表情鍵盤,自定義View的高度肯定也要變化,點擊更多按鈕時也是一樣,所以,我們先寫個高度變化的方法
其實底部的view,我們可以用一個activeView表示底部到底是什么View,方法的話是傳入一個View,就直接能改變自定義View的高度來適應底部的activeView,多加的兩個方法,記得要加個屬性,就是activeView,類型是UIView;
- (void)willShowBottomView:(UIView *)bottomView { if (![self.activeView isEqual:bottomView]) { CGFloat bottomHeight = bottomView ? bottomView.frame.size.height : 0; [self willShowBottomHeight:bottomHeight]; if (bottomView) { CGRect rect = bottomView.frame; rect.origin.y = CGRectGetMaxY(self.backgroundImageView.frame); bottomView.frame = rect; [self addSubview:bottomView]; } if (self.activeView) { [self.activeView removeFromSuperview]; } self.activeView = bottomView; } } - (void)willShowBottomHeight:(CGFloat)bottomHeight { CGRect fromFrame = self.frame; CGFloat toHeight = self.backgroundImageView.frame.size.height + bottomHeight; CGRect toFrame = CGRectMake(fromFrame.origin.x, fromFrame.origin.y + (fromFrame.size.height - toHeight), fromFrame.size.width, toHeight); self.frame = toFrame; }
接下來,我們創建表情鍵盤,這個是我網上找的(我不會寫表情鍵盤...),自己看git里面的FaceView的文件夾,順便試試上面的改變frame的方法
#import "BCKeyBoard.h" #import "DXFaceView.h" #define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width) #define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height) #define kBCTextViewHeight 36 /**< 底部textView的高度 */ #define kHorizontalPadding 8 /**< 橫向間隔 */ #define kVerticalPadding 5 /**< 縱向間隔 */ @interface BCKeyBoard() <UITextViewDelegate,DXFaceDelegate> @property (nonatomic,strong)UIButton *faceBtn; @property (nonatomic,strong)UIButton *moreBtn; @property (nonatomic,strong)BCTextView *textView; @property (nonatomic,strong)UIImageView *backgroundImageView; @property (nonatomic,strong)UIView *faceView; @property (nonatomic,strong)UIView *activeView; @end @implementation BCKeyBoard - (instancetype)initWithFrame:(CGRect)frame { if (frame.size.height < (kVerticalPadding * 2 + kBCTextViewHeight)) { frame.size.height = kVerticalPadding * 2 + kBCTextViewHeight; } self = [super initWithFrame:frame]; if (self) { [self createUI]; } return self; } - (void)setFrame:(CGRect)frame { if (frame.size.height < (kVerticalPadding * 2 + kBCTextViewHeight)) { frame.size.height = kVerticalPadding * 2 + kBCTextViewHeight; } [super setFrame:frame]; } - (void)createUI{ //鍵盤高度改變是調用 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil]; self.backgroundImageView = [[UIImageView alloc] initWithFrame:self.bounds]; self.backgroundImageView.userInteractionEnabled = YES; self.backgroundImageView.image = [[UIImage imageNamed:@"messageToolbarBg"] stretchableImageWithLeftCapWidth:0.5 topCapHeight:10]; //表情按鈕 self.faceBtn = [UIButton buttonWithType:UIButtonTypeCustom]; self.faceBtn.frame = CGRectMake(kHorizontalPadding,kHorizontalPadding, 30, 30); [self.faceBtn addTarget:self action:@selector(willShowFaceView:) forControlEvents:UIControlEventTouchUpInside]; [self.faceBtn setBackgroundImage:[UIImage imageNamed:@"chatBar_face"] forState:UIControlStateNormal]; [self.faceBtn setBackgroundImage:[UIImage imageNamed:@"chatBar_keyboard"] forState:UIControlStateSelected]; [self addSubview:self.faceBtn]; //文本 self.textView = [[BCTextView alloc] initWithFrame:CGRectMake(CGRectGetMaxX(self.faceBtn.frame)+kHorizontalPadding, kHorizontalPadding, self.bounds.size.width - 4*kHorizontalPadding - 30*2, 30)]; self.textView.placeholderColor = [UIColor lightGrayColor]; self.textView.returnKeyType = UIReturnKeySend; self.textView.scrollEnabled = NO; self.textView.backgroundColor = [UIColor clearColor]; self.textView.layer.borderColor = [UIColor colorWithWhite:0.8f alpha:1.0f].CGColor; self.textView.layer.borderWidth = 0.65f; self.textView.layer.cornerRadius = 6.0f; self.textView.delegate = self; //更多按鈕 self.moreBtn = [UIButton buttonWithType:UIButtonTypeCustom]; self.moreBtn.frame = CGRectMake(CGRectGetMaxX(self.textView.frame)+kHorizontalPadding,kHorizontalPadding,30,30); [self.moreBtn addTarget:self action:@selector(willShowMoreView:) forControlEvents:UIControlEventTouchUpInside]; [self.moreBtn setBackgroundImage:[UIImage imageNamed:@"chatBar_more"] forState:UIControlStateNormal]; [self.moreBtn setBackgroundImage:[UIImage imageNamed:@"chatBar_keyboard"] forState:UIControlStateSelected]; [self addSubview:self.backgroundImageView]; [self.backgroundImageView addSubview:self.textView]; [self.backgroundImageView addSubview:self.faceBtn]; [self.backgroundImageView addSubview:self.moreBtn]; if (!self.faceView) { self.faceView = [[DXFaceView alloc] initWithFrame:CGRectMake(0, (kHorizontalPadding * 2 + 30), self.frame.size.width, 200)]; [(DXFaceView *)self.faceView setDelegate:self]; self.faceView.backgroundColor = [UIColor whiteColor]; self.faceView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin; } } - (void)keyboardWillChangeFrame:(NSNotification *)notification{ NSDictionary *userInfo = notification.userInfo; CGRect endFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; CGFloat duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]; //動畫 void(^animations)() = ^{ CGRect frame = self.frame; frame.origin.y = endFrame.origin.y - self.bounds.size.height; self.frame = frame; }; void(^completion)(BOOL) = ^(BOOL finished){ }; [UIView animateWithDuration:duration delay:0.0f options:(curve << 16 | UIViewAnimationOptionBeginFromCurrentState) animations:animations completion:completion]; } - (void)willShowBottomView:(UIView *)bottomView { if (![self.activeView isEqual:bottomView]) { CGFloat bottomHeight = bottomView ? bottomView.frame.size.height : 0; [self willShowBottomHeight:bottomHeight]; if (bottomView) { CGRect rect = bottomView.frame; rect.origin.y = CGRectGetMaxY(self.backgroundImageView.frame); bottomView.frame = rect; [self addSubview:bottomView]; } if (self.activeView) { [self.activeView removeFromSuperview]; } self.activeView = bottomView; } } - (void)willShowBottomHeight:(CGFloat)bottomHeight { CGRect fromFrame = self.frame; CGFloat toHeight = self.backgroundImageView.frame.size.height + bottomHeight; CGRect toFrame = CGRectMake(fromFrame.origin.x, fromFrame.origin.y + (fromFrame.size.height - toHeight), fromFrame.size.width, toHeight); self.frame = toFrame; } #pragma mark 表情鍵盤的代理方法 - (void)sendFace { } - (void)selectedFacialView:(NSString *)str isDelete:(BOOL)isDelete{ } //顯示表情鍵盤 - (void)willShowFaceView:(UIButton *)btn{ btn.selected = !btn.selected; if(btn.selected == YES){ [self willShowBottomView:self.faceView]; [self.textView resignFirstResponder]; }else{ [self willShowBottomView:nil]; [self.textView becomeFirstResponder]; } } //顯示擴展鍵盤 - (void)willShowMoreView:(UIButton *)btn{ } @end
運行效果
今天就到這里啦,有什么問題,可以在評論里面發給我哦,等有時間繼續寫啦