带大家一步一步的封装一个聊天键盘
来源:互联网 发布:cf出现网络异常 编辑:程序博客网 时间:2024/06/06 02:12
众所周知,一个聊天键盘,肯定要有表情,发送图片啊,语音啊,视频什么的,我封装的就只有表情(是emoji),其他几个扩展的,放在一个view里,等以后在去添加功能
好吧,我们开始,首先要思考封装一个这样的聊天键盘,我们需要什么,肯定需要一个表情按钮,UItextView,还有一个扩展的view,而UITextView可能需要有占位文字,所以我们首先自己定制有占位文字的UITextView
继承UITextView创建一个自定义的UITextView,我的叫BCTextView
http://pan.baidu.com/s/1c1berb6 这是表情和图片的下载地址
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
运行效果
首先,我们先把扩展的View写了,扩展的View我是用的自定义的View,其实也就是几张图片而已啦,继承UIView自定义一个View
我的想法是,封装一个view,传入一个数组,就能显示一排间隔相等的图片,我定义的时每一行有4个button,有5个间隔,每个间隔的距离就应该是屏幕总宽度减去4*button的宽度在除以5,这样创建button,在给button绑定tag,方便知道是点击了哪个button
BCMoreView.h文件
#import <UIKit/UIKit.h>@protocol BCMoreViewDelegate <NSObject>- (void)didselectImageView:(NSInteger)index;@end@interface BCMoreView : UIView@property (nonatomic,strong)NSArray *imageArray;@property (nonatomic,weak)id <BCMoreViewDelegate> delegate;@end
BCMoreView.m文件
@implementation BCMoreView- (instancetype)initWithFrame:(CGRect)frame{ if(self = [super initWithFrame:frame]){ } return self;}- (void)setImageArray:(NSArray *)imageArray{ CGFloat padding = ([UIScreen mainScreen].bounds.size.width - 42*4)/5; for(int i=0;i<imageArray.count;i++){ int clo = i % 4; int lin = i / 4; UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; btn.frame = CGRectMake(padding + (padding+42)*clo,20+(padding+42)*lin, 42, 42); btn.tag = i; [btn setBackgroundImage:[UIImage imageNamed:imageArray[i]] forState:UIControlStateNormal]; [btn addTarget:self action:@selector(selectImage:) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:btn]; }}- (void)selectImage:(UIButton *)btn{ if(self.delegate){ [self.delegate didselectImageView:btn.tag]; }}@end
好,更多view也写好了,现在我们回到keyboardView,将这个自定义的View加上去
keyboardView.m文件
#import "BCKeyBoard.h"#import "DXFaceView.h"#import "BCMoreView.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,BCMoreViewDelegate>@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;@property (nonatomic,strong)UIView *moreView;@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; } if (!self.moreView) { self.moreView = [[BCMoreView alloc] initWithFrame:CGRectMake(0, (kHorizontalPadding * 2 + 30), self.frame.size.width, 200)]; self.moreView.backgroundColor = [UIColor whiteColor]; [(BCMoreView *)self.moreView setDelegate:self]; self.moreView.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{ }//是点击了哪个图片- (void)didselectImageView:(NSInteger)index{}@end
其实显示扩展键盘和显示表情键盘是一样的,只不过要多传个数组,告诉自定义的View,你要显示什么,我的想法是,这个显示什么应该使用者自己去决定,所以我决定提供个外部接口,让使用者自己去传入什么样的数组,占位文字和文字颜色也让使用者自己去定义
在BCKeyBoard.h文件中加一个叫imageArray的数组属性
#import "BCKeyBoard.h"#import "DXFaceView.h"#import "BCMoreView.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,BCMoreViewDelegate>@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;@property (nonatomic,strong)UIView *moreView;@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; } if (!self.moreView) { self.moreView = [[BCMoreView alloc] initWithFrame:CGRectMake(0, (kHorizontalPadding * 2 + 30), self.frame.size.width, 200)]; self.moreView.backgroundColor = [UIColor whiteColor]; [(BCMoreView *)self.moreView setDelegate:self]; self.moreView.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{ btn.selected = !btn.selected; if(btn.selected == YES){ [self willShowBottomView:self.moreView]; [self.textView resignFirstResponder]; [(BCMoreView *)self.moreView setImageArray:self.imageArray]; }else{ [self willShowBottomView:nil]; [self.textView becomeFirstResponder]; }}//是点击了哪个图片- (void)didselectImageView:(NSInteger)index{}@end
其实上次封装的键盘有个小bug
其实解决这个bug很简单,就是在textView刚开始编辑时,将2个按钮的selected都变成NO,底部的activeView置成nil
- (void)textViewDidBeginEditing:(UITextView *)textView{ [self willShowBottomView:nil]; self.faceBtn.selected = NO; self.moreBtn.selected = NO;}
接下来就是最重要的了,将文字和表情传入到控制器中,我用的是代理传值,表情的处理是网上找的,那什么时候将值传到控制器呢,我的做法和QQ是一样的,将return键变成发送键,在textView的代理方法
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text中,那怎么判断点了发送键呢,其实就是判断换行,点击发送键就是换行字符
在发送后要将textView的内容置空,textView的高度也要随输入字符的多少改变高度,我的想法是传入textView,返回一个高度所以我就写了这个方法
- (CGFloat)getTextViewContentH:(UITextView *)textView{ return ceilf([textView sizeThatFits:textView.frame.size].height);}
但是光有这个方法是不够,还要有个改变整个view的frame和textView的frame的方法,我的想法是传入一个高度,就能随之改变view的frame和textView的frame,所以写了这个方法,_lastHeight代表上次的高度,因为textView的高度随着输入文字而改变,超过一行才改变高度,没超过一行还是上一次
的高度,代理方法是把高度返回给控制器
- (void)changeFrame:(CGFloat)height{ if (height == _lastHeight) { return; } else{ CGFloat changeHeight = height - _lastHeight; CGRect rect = self.frame; rect.size.height += changeHeight; rect.origin.y -= changeHeight; self.frame = rect; rect = self.backgroundImageView.frame; rect.size.height += changeHeight; self.backgroundImageView.frame = rect; [self.textView setContentOffset:CGPointMake(0.0f, (self.textView.contentSize.height - self.textView.frame.size.height) / 2) animated:YES]; CGRect frame = self.textView.frame; frame.size.height = height; self.textView.frame = frame; _lastHeight = height; if (self.delegate && [self.delegate respondsToSelector:@selector(returnHeight:)]) { [self.delegate returnHeight:height]; } } }
最后BCKeyBoard.h
#import <UIKit/UIKit.h>@protocol BCKeyBoardDelegate <NSObject>/** 发送的文字 */- (void)didSendText:(NSString *)text;/** 回调返回高度 */- (void)returnHeight:(CGFloat)height;@end@interface BCKeyBoard : UIView@property (nonatomic,weak)id <BCKeyBoardDelegate> delegate;@property (nonatomic,strong)NSArray *imageArray; /**< 点击加号弹出的View中的图片数组 */@property (nonatomic,strong)NSString *placeholder; /**< 占位文字 */@property (nonatomic,strong)UIColor *placeholderColor; /**< 占位文字颜色 */@end
BCKeyBoard.m
#import "BCKeyBoard.h"#import "BCTextView.h"#import "Const.h"#import "DXFaceView.h"#import "BCMoreView.h"@interface BCKeyBoard () <UITextViewDelegate,DXFaceDelegate,BCMoreViewDelegate>@property (nonatomic,strong)UIImageView *backgroundImageView;@property (nonatomic,strong)UIButton *faceBtn;@property (nonatomic,strong)UIButton *moreBtn;@property (nonatomic,strong)BCTextView *textView;@property (nonatomic,strong)UIView *faceView;@property (nonatomic,assign)BOOL isTop;@property (nonatomic,strong)UIView *moreView;@property (nonatomic,assign)CGFloat lastHeight;//拓展的view@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{ _lastHeight = 30; //注册键盘改变是调用 [[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 = self.placeholderColor; 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(willShowactiveView:) 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; } if (!self.moreView) { self.moreView = [[BCMoreView alloc] initWithFrame:CGRectMake(0, (kHorizontalPadding * 2 + 30), self.frame.size.width, 200)]; self.moreView.backgroundColor = [UIColor whiteColor]; [(BCMoreView *)self.moreView setDelegate:self]; self.moreView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin; }}- (void)changeFrame:(CGFloat)height{ if (height == _lastHeight) { return; } else{ CGFloat changeHeight = height - _lastHeight; CGRect rect = self.frame; rect.size.height += changeHeight; rect.origin.y -= changeHeight; self.frame = rect; rect = self.backgroundImageView.frame; rect.size.height += changeHeight; self.backgroundImageView.frame = rect; [self.textView setContentOffset:CGPointMake(0.0f, (self.textView.contentSize.height - self.textView.frame.size.height) / 2) animated:YES]; CGRect frame = self.textView.frame; frame.size.height = height; self.textView.frame = frame; _lastHeight = height; if (self.delegate && [self.delegate respondsToSelector:@selector(returnHeight:)]) { [self.delegate returnHeight:height]; } }}- (void)setPlaceholder:(NSString *)placeholder{ self.textView.placeholder = placeholder;}- (void)setPlaceholderColor:(UIColor *)placeholderColor{ self.textView.placeholderColor = placeholderColor;}- (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];}#pragma mark 表情View- (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]; }}#pragma mark 表更多View- (void)willShowactiveView:(UIButton *)btn{ btn.selected = !btn.selected; if(btn.selected == YES){ [self willShowBottomView:self.moreView]; [self.textView resignFirstResponder]; [(BCMoreView *)self.moreView setImageArray:self.imageArray]; }else{ [self willShowBottomView:nil]; [self.textView becomeFirstResponder]; }}- (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; if (self.delegate && [self.delegate respondsToSelector:@selector(returnHeight:)]) { [self.delegate returnHeight:toHeight]; }}- (CGFloat)getTextViewContentH:(UITextView *)textView{ return ceilf([textView sizeThatFits:textView.frame.size].height);}- (void)textViewDidBeginEditing:(UITextView *)textView{ [self willShowBottomView:nil]; self.faceBtn.selected = NO; self.moreBtn.selected = NO;}- (void)willShowKeyboardFromFrame:(CGRect)beginFrame toFrame:(CGRect)toFrame{ if (beginFrame.origin.y == [[UIScreen mainScreen] bounds].size.height) { [self willShowBottomHeight:toFrame.size.height]; if (self.activeView) { [self.activeView removeFromSuperview]; } self.activeView = nil; } else if(toFrame.origin.y == [[UIScreen mainScreen] bounds].size.height) { [self willShowBottomHeight:0]; } else{ [self willShowBottomHeight:toFrame.size.height]; }}- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{ if ([text isEqualToString:@"\n"]) { if ([self.delegate respondsToSelector:@selector(didSendText:)]) { [self.delegate didSendText:textView.text]; self.textView.text = @""; [self changeFrame:ceilf([textView sizeThatFits:textView.frame.size].height)]; } return NO; } return YES;}- (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)textViewDidChange:(UITextView *)textView{ [self changeFrame:ceilf([textView sizeThatFits:textView.frame.size].height)];}- (void)selectedFacialView:(NSString *)str isDelete:(BOOL)isDelete{ NSString *chatText = self.textView.text; if (!isDelete && str.length > 0) { self.textView.text = [NSString stringWithFormat:@"%@%@",chatText,str]; } else { if (chatText.length >= 2) { NSString *subStr = [chatText substringFromIndex:chatText.length-2]; if ([(DXFaceView *)self.faceView stringIsFace:subStr]) { self.textView.text = [chatText substringToIndex:chatText.length-2]; [self textViewDidChange:self.textView]; return; } } if (chatText.length > 0) { self.textView.text = [chatText substringToIndex:chatText.length-1]; } } [self textViewDidChange:self.textView];}- (void)sendFace{ NSString *chatText = self.textView.text; if (chatText.length > 0) { if ([self.delegate respondsToSelector:@selector(didSendText:)]) { [self.delegate didSendText:chatText]; self.textView.text = @""; [self changeFrame:ceilf([self.textView sizeThatFits:self.textView.frame.size].height)]; } }}- (void)didselectImageView:(NSInteger)index{ //这里是更多的view中选择了哪个图片 NSLog(@"%ld",(long)index);}- (void)dealloc{ [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil];}@end
运行效果
需求:点击图片按钮,弹出actionsheet控件,选择拍摄还是从图片库选择
好吧,不啰嗦了,直接上代码
- (void)didselectImageView:(NSInteger)index{ switch (index) { case 0: [self createActionSheet]; break; default: break; }}- (void)createActionSheet{ UIActionSheet *action=[[UIActionSheet alloc] initWithTitle:@"选取照片" delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"从摄像头选取", @"从图片库选择",nil]; [action showInView:self];}- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{ switch (buttonIndex) { case 0: [self openCamera]; break; case 1: [self openLibary]; break; default: break; }}- (void)openCamera{ //打开系统相机 if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){ UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.delegate = self; picker.allowsEditing = YES; picker.sourceType = UIImagePickerControllerSourceTypeCamera; [self.currentCtr presentViewController:picker animated:YES completion:nil]; }}- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{ UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage]; if([self.delegate respondsToSelector:@selector(returnImage:)]){ [self.delegate returnImage:image]; } UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil); [self.currentCtr dismissViewControllerAnimated:YES completion:nil]; }- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{ [self.currentCtr dismissViewControllerAnimated:YES completion:nil];}- (void)openLibary{ if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]){ UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.delegate = self; picker.allowsEditing = YES; picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; [self.currentCtr presentViewController:picker animated:YES completion:nil]; }}
上次封装的代理方法可以将点击了第几张图片的事件传回自定义的View,也就是BCKeyBoard,根据 - (void)didselectImageView:(NSInteger)index方法中的index来判断点击了第几个图片
这里我们用switch,因为它比较快,点击了第一个图片,就创建一个actionsheet,利用actionsheet的代理方法
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex来判断点击了第几个按钮
从而选择打开相机还是打开相册,在这里我发现个问题,因为在view里的对象是view,而不是viewcontroller所以不能使用presentViewController方法,虽然可以使用代理将点击事件传到控制器再在控制器去打开相机和相册
但是,那不是我想要的,我想把所有的逻辑都封装在自定义View里面,突然,灵光一闪,我把控制器当做一个属性传给自定义View,不就能调用外部控制器去使用presentViewController方法了(真是个天才,哈哈),还需要写个代理方法
将拍摄的照片和从相册里面选择的照片传回控制器,以便使用者使用
最后BCKeyBoard.h文件
#import <UIKit/UIKit.h>@protocol BCKeyBoardDelegate <NSObject>/** 发送的文字 */- (void)didSendText:(NSString *)text;/** 回调返回高度 */- (void)returnHeight:(CGFloat)height;/** 回调返回的图片 */- (void)returnImage:(UIImage *)image;@end@interface BCKeyBoard : UIView@property (nonatomic,weak)id <BCKeyBoardDelegate> delegate;@property (nonatomic,strong)NSArray *imageArray; /**< 点击加号弹出的View中的图片数组 */@property (nonatomic,strong)NSString *placeholder; /**< 占位文字 */@property (nonatomic,strong)UIColor *placeholderColor; /**< 占位文字颜色 */@property (nonatomic,strong)UIViewController *currentCtr;@end
BCKeyBoard.m文件
#import "BCKeyBoard.h"#import "BCTextView.h"#import "DXFaceView.h"#import "BCMoreView.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,BCMoreViewDelegate,UIActionSheetDelegate,UINavigationControllerDelegate,UIImagePickerControllerDelegate>@property (nonatomic,strong)UIImageView *backgroundImageView;@property (nonatomic,strong)UIButton *faceBtn;@property (nonatomic,strong)UIButton *moreBtn;@property (nonatomic,strong)BCTextView *textView;@property (nonatomic,strong)UIView *faceView;@property (nonatomic,strong)UIView *moreView;@property (nonatomic,assign)CGFloat lastHeight;@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{ _lastHeight = 30; //注册键盘改变是调用 [[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 = self.placeholderColor; 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(willShowactiveView:) 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; } if (!self.moreView) { self.moreView = [[BCMoreView alloc] initWithFrame:CGRectMake(0, (kHorizontalPadding * 2 + 30), self.frame.size.width, 200)]; self.moreView.backgroundColor = [UIColor whiteColor]; [(BCMoreView *)self.moreView setDelegate:self]; self.moreView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin; }}- (void)changeFrame:(CGFloat)height{ if (height == _lastHeight) { return; } else{ CGFloat changeHeight = height - _lastHeight; CGRect rect = self.frame; rect.size.height += changeHeight; rect.origin.y -= changeHeight; self.frame = rect; rect = self.backgroundImageView.frame; rect.size.height += changeHeight; self.backgroundImageView.frame = rect; [self.textView setContentOffset:CGPointMake(0.0f, (self.textView.contentSize.height - self.textView.frame.size.height) / 2) animated:YES]; CGRect frame = self.textView.frame; frame.size.height = height; self.textView.frame = frame; _lastHeight = height; if (self.delegate && [self.delegate respondsToSelector:@selector(returnHeight:)]) { [self.delegate returnHeight:height]; } }}- (void)setPlaceholder:(NSString *)placeholder{ self.textView.placeholder = placeholder;}- (void)setPlaceholderColor:(UIColor *)placeholderColor{ self.textView.placeholderColor = placeholderColor;}- (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];}#pragma mark 表情View- (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]; }}#pragma mark 表更多View- (void)willShowactiveView:(UIButton *)btn{ btn.selected = !btn.selected; if(btn.selected == YES){ [self willShowBottomView:self.moreView]; [self.textView resignFirstResponder]; [(BCMoreView *)self.moreView setImageArray:self.imageArray]; }else{ [self willShowBottomView:nil]; [self.textView becomeFirstResponder]; }}- (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; if (self.delegate && [self.delegate respondsToSelector:@selector(returnHeight:)]) { [self.delegate returnHeight:toHeight]; }}- (CGFloat)getTextViewContentH:(UITextView *)textView{ return ceilf([textView sizeThatFits:textView.frame.size].height);}- (void)textViewDidBeginEditing:(UITextView *)textView{ [self willShowBottomView:nil]; self.faceBtn.selected = NO; self.moreBtn.selected = NO;}- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{ if ([text isEqualToString:@"\n"]) { if ([self.delegate respondsToSelector:@selector(didSendText:)]) { [self.delegate didSendText:textView.text]; self.textView.text = @""; [self changeFrame:ceilf([textView sizeThatFits:textView.frame.size].height)]; } return NO; } return YES;}- (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)textViewDidChange:(UITextView *)textView{ [self changeFrame:ceilf([textView sizeThatFits:textView.frame.size].height)];}- (void)selectedFacialView:(NSString *)str isDelete:(BOOL)isDelete{ NSString *chatText = self.textView.text; if (!isDelete && str.length > 0) { self.textView.text = [NSString stringWithFormat:@"%@%@",chatText,str]; } else { if (chatText.length >= 2) { NSString *subStr = [chatText substringFromIndex:chatText.length-2]; if ([(DXFaceView *)self.faceView stringIsFace:subStr]) { self.textView.text = [chatText substringToIndex:chatText.length-2]; [self textViewDidChange:self.textView]; return; } } if (chatText.length > 0) { self.textView.text = [chatText substringToIndex:chatText.length-1]; } } [self textViewDidChange:self.textView];}- (void)sendFace{ NSString *chatText = self.textView.text; if (chatText.length > 0) { if ([self.delegate respondsToSelector:@selector(didSendText:)]) { [self.delegate didSendText:chatText]; self.textView.text = @""; [self changeFrame:ceilf([self.textView sizeThatFits:self.textView.frame.size].height)]; } }}- (void)didselectImageView:(NSInteger)index{ switch (index) { case 0: [self createActionSheet]; break; default: break; }}- (void)createActionSheet{ UIActionSheet *action=[[UIActionSheet alloc] initWithTitle:@"选取照片" delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"从摄像头选取", @"从图片库选择",nil]; [action showInView:self];}- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{ switch (buttonIndex) { case 0: [self openCamera]; break; case 1: [self openLibary]; break; default: break; }}- (void)openCamera{ //打开系统相机 if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){ UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.delegate = self; picker.allowsEditing = YES; picker.sourceType = UIImagePickerControllerSourceTypeCamera; [self.currentCtr presentViewController:picker animated:YES completion:nil]; }}- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{ UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage]; if([self.delegate respondsToSelector:@selector(returnImage:)]){ [self.delegate returnImage:image]; } UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil); [self.currentCtr dismissViewControllerAnimated:YES completion:nil]; }- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{ [self.currentCtr dismissViewControllerAnimated:YES completion:nil];}- (void)openLibary{ if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]){ UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.delegate = self; picker.allowsEditing = YES; picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; [self.currentCtr presentViewController:picker animated:YES completion:nil]; }}- (void)dealloc{ [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil];}@end
viewController里面的使用方法
#import "ViewController.h"#import "BCKeyBoard.h"@interface ViewController () <BCKeyBoardDelegate>@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; NSArray *array = @[@"chatBar_colorMore_photoSelected",@"chatBar_colorMore_audioCall",@"chatBar_colorMore_location",@"chatBar_colorMore_video.png",@"chatBar_colorMore_video.png",@"chatBar_colorMore_video.png"]; BCKeyBoard *bc = [[BCKeyBoard alloc] initWithFrame:CGRectMake(0, [UIScreen mainScreen].bounds.size.height - 46, [UIScreen mainScreen].bounds.size.width,46)]; bc.delegate = self; bc.imageArray = array; bc.placeholder = @"我来说几句"; bc.currentCtr = self; bc.placeholderColor = [UIColor colorWithRed:133/255 green:133/255 blue:133/255 alpha:0.5]; bc.backgroundColor = [UIColor clearColor]; [self.view addSubview:bc];}- (void)didSendText:(NSString *)text{ NSLog(@"%@",text);}- (void)returnHeight:(CGFloat)height{ NSLog(@"%f",height);}- (void)returnImage:(UIImage *)image{ UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)]; imageView.image = image; [self.view addSubview:imageView];}@end
运行效果
- 带大家一步一步的封装一个聊天键盘
- 带大家一步一步的封装一个聊天键盘(一)
- 带大家一步一步封装一个聊天键盘(二)
- 一步一步封装一个简洁高效可拓展的Adapter
- 一步一步带你写一个dagger2的Demo
- 一步一步带你搭建一个“摩登”的前端开发环境
- 自己实现的一个directxinput键盘的封装
- 带小数点的键盘
- 封装一个带toolbar的活动,toolbar只写一次
- #jquery 和 animate 封装一个带动画的弹框
- 利用LruCache封装一个自带三级缓存的ImageLoader
- 一步一步的来封装自己的RecycleView
- 一步一步封装自己的HtmlHelper组件:BootstrapHelper
- 一个UDP的聊天
- 将Spring推下神坛(仿造一个中国式Spring ,教大家一步一步从代码的角度理解 Ioc)
- #解决仿微信聊天界面键盘遮盖聊天的界面
- 给大家推荐一个【webview和js的交互】封装,很好用~~~
- 一步一步给你的 Android app 加入聊天功能
- nginx在windows下配置反向代理
- Android 线程池 工作调度
- codeforces 614B
- android monkey测试
- 异步套接字实现
- 带大家一步一步的封装一个聊天键盘
- [实战] 用数人云,部署弹性 ELK 集群就五步
- apache多站点配置
- 架构一个后台管理系统的技术所需要的技术
- STL_算法_逆转(reverse,reverse_copy)
- HTML之表单标签
- 【JS学习笔记】JS基础上:数据类型
- 四种常见的 POST 提交数据方式
- sql where 1=1 规范代码