微信大家基本上都用过,今天要做的就是微信的聊天工具条。聊天工具条还是比较复杂的,其中包括发送表情,发送文字,发送图片,发送声音,拍照等等功能,下面给出发送录音,文字,表情的代码,其他的和这几样类似。还是那句话百字不如一图,先来几张效果图吧。
在封装聊天工具条的的时候表情键盘是之前封装好的,所以拿过来就可以用的啦。因为不管是工具条还是表情键盘都是用约束来控件大小的,所以横屏也是没问题的,在大屏手机上也是没问题的。下面将会一步步讲解如何封装下面的聊天工具条。主要是对工具条的封装,表情键盘在这就不做讲解了。
一、toolview预留的接口
在封装toolview中主要用到block回调,读者可以根据自己的个人习惯来选择是block回调,还是委托回调或者是目标动作回调(笔者更喜欢block回调),下面的代码是toolview给调用者提供的接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
//
// toolview.h
// mecromessage
//
// created by (青玉伏案)on 14-9-22.
// copyright (c) 2014年 mrli. all rights reserved.
//
#import <uikit/uikit.h>
//定义block类型把toolview中textview中的文字传入到controller中
typedef void (^mytextblock) (nsstring *mytext);
//录音时的音量
typedef void (^audiovolumeblock) (cgfloat volume);
//录音存储地址
typedef void (^audiourlblock) (nsurl *audiourl);
//改变根据文字改变textview的高度
typedef void (^contentsizeblock)(cgsize contentsize);
//录音取消的回调
typedef void (^cancelrecordblock)( int flag);
@interface toolview : uiview<uitextviewdelegate,avaudiorecorderdelegate>
//设置mytextblock
-( void ) setmytextblock:(mytextblock)block;
//设置声音回调
-( void ) setaudiovolumeblock:(audiovolumeblock) block;
//设置录音地址回调
-( void ) setaudiourlblock:(audiourlblock) block;
-( void )setcontentsizeblock:(contentsizeblock) block;
-( void )setcancelrecordblock:(cancelrecordblock)block;
-( void ) changefunctionheight: ( float ) height;
@end
|
二、初始化toolview中所需的控件
1.为了更好的封装我们的组件,在.h中预留接口,在toolview.m的延展中添加我们要使用的组件(私有属性),延展代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
@interface toolview()
//最左边发送语音的按钮
@property (nonatomic, strong) uibutton *voicechangebutton;
//发送语音的按钮
@property (nonatomic, strong) uibutton *sendvoicebutton;
//文本视图
@property (nonatomic, strong) uitextview *sendtextview;
//切换键盘
@property (nonatomic, strong) uibutton *changekeyboardbutton;
//more
@property (nonatomic, strong) uibutton *morebutton;
//键盘坐标系的转换
@property (nonatomic, assign) cgrect endkeyboardframe;
//表情键盘
@property (nonatomic, strong) functionview *functionview;
//more
@property (nonatomic, strong) moreview *moreview;
//数据model
@property (strong, nonatomic) imagemodelclass *imagemode;
@property (strong, nonatomic)historyimage *tempimage;
//传输文字的block回调
@property (strong, nonatomic) mytextblock textblock;
//contentsinz
@property (strong, nonatomic) contentsizeblock sizeblock;
//传输volome的block回调
@property (strong, nonatomic) audiovolumeblock volumeblock;
//传输录音地址
@property (strong, nonatomic) audiourlblock urlblock;
//录音取消
@property (strong, nonatomic) cancelrecordblock cancelblock;
//添加录音功能的属性
@property (strong, nonatomic) avaudiorecorder *audiorecorder;
@property (strong, nonatomic) nstimer *timer;
@property (strong, nonatomic) nsurl *audioplayurl;
@end
|
2.接受相应的block回调,把block传入toolview中,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
-( void )setmytextblock:(mytextblock)block
{
self.textblock = block;
}
-( void )setaudiovolumeblock:(audiovolumeblock)block
{
self.volumeblock = block;
}
-( void )setaudiourlblock:(audiourlblock)block
{
self.urlblock = block;
}
-( void )setcontentsizeblock:(contentsizeblock)block
{
self.sizeblock = block;
}
-( void )setcancelrecordblock:(cancelrecordblock)block
{
self.cancelblock = block;
}
|
3.控件的初始化,纯代码添加toolview中要用到的组件(分配内存,配置相应的属性),因为是自定义组件的封装,所以我们的storyboard就用不上啦,添加控件的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
//控件的初始化
-( void ) addsubview
{
self.voicechangebutton = [[uibutton alloc] initwithframe:cgrectzero];
[self.voicechangebutton setimage:[uiimage imagenamed:@ "chat_bottom_voice_press.png" ] forstate:uicontrolstatenormal];
[self.voicechangebutton addtarget:self action:@selector(tapvoicechangebutton:) forcontrolevents:uicontroleventtouchupinside];
[self addsubview:self.voicechangebutton];
self.sendvoicebutton = [[uibutton alloc] initwithframe:cgrectzero];
[self.sendvoicebutton setbackgroundimage:[uiimage imagenamed:@ "chat_bottom_textfield.png" ] forstate:uicontrolstatenormal];
[self.sendvoicebutton settitlecolor:[uicolor blackcolor] forstate:uicontrolstatenormal];
[self.sendvoicebutton settitle:@ "按住说话" forstate:uicontrolstatenormal];
[self.sendvoicebutton addtarget:self action:@selector(tapsendvoicebutton:) forcontrolevents:uicontroleventtouchupinside];
self.sendvoicebutton.hidden = yes;
[self addsubview:self.sendvoicebutton];
self.sendtextview = [[uitextview alloc] initwithframe:cgrectzero];
self.sendtextview.delegate = self;
[self addsubview:self.sendtextview];
self.changekeyboardbutton = [[uibutton alloc] initwithframe:cgrectzero];
[self.changekeyboardbutton setimage:[uiimage imagenamed:@ "chat_bottom_smile_nor.png" ] forstate:uicontrolstatenormal];
[self.changekeyboardbutton addtarget:self action:@selector(tapchangekeyboardbutton:) forcontrolevents:uicontroleventtouchupinside];
[self addsubview:self.changekeyboardbutton];
self.morebutton = [[uibutton alloc] initwithframe:cgrectzero];
[self.morebutton setimage:[uiimage imagenamed:@ "chat_bottom_up_nor.png" ] forstate:uicontrolstatenormal];
[self.morebutton addtarget:self action:@selector(tapmorebutton:) forcontrolevents:uicontroleventtouchupinside];
[self addsubview:self.morebutton];
[self adddone];
//实例化functionview
self.functionview = [[functionview alloc] initwithframe:cgrectmake(0, 0, 320, 216)];
self.functionview.backgroundcolor = [uicolor blackcolor];
//设置资源加载的文件名
self.functionview.plistfilename = @ "emoticons" ;
__weak __block toolview *copy_self = self;
//获取图片并显示
[self.functionview setfunctionblock:^(uiimage *image, nsstring *imagetext)
{
nsstring *str = [nsstring stringwithformat:@ "%@%@" ,copy_self.sendtextview.text, imagetext];
copy_self.sendtextview.text = str;
//把使用过的图片存入sqlite
nsdata *imagedata = uiimagepngrepresentation(image);
[copy_self.imagemode save:imagedata imagetext:imagetext];
}];
//给sendtextview添加轻击手势
uitapgesturerecognizer *tapgesture = [[uitapgesturerecognizer alloc] initwithtarget:self action:@selector(tapgesture:)];
[self.sendtextview addgesturerecognizer:tapgesture];
//给sendvoicebutton添加长按手势
uilongpressgesturerecognizer *longpress = [[uilongpressgesturerecognizer alloc] initwithtarget:self action:@selector(sendvoicebuttonlongpress:)];
//设置长按时间
longpress.minimumpressduration = 0.2;
[self.sendvoicebutton addgesturerecognizer:longpress];
//实例化moreview
self.moreview = [[moreview alloc] initwithframe:cgrectmake(0, 0, 0, 0)];
self.moreview.backgroundcolor = [uicolor blackcolor];
[self.moreview setmoreblock:^(nsinteger index) {
nslog(@ "moreindex = %d" ,( int )index);
}];
}
|
4.给我们的控件添加相应的约束,为了适合不同的屏幕,所以自动布局是少不了的。当然啦给控件添加约束也必须是手写代码啦,添加约束的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
//给控件加约束
-( void )addconstraint
{
//给voicebutton添加约束
self.voicechangebutton.translatesautoresizingmaskintoconstraints = no;
nsarray *voiceconstrainth = [nslayoutconstraint constraintswithvisualformat:@ "h:|-5-[_voicechangebutton(30)]" options:0 metrics:0 views:nsdictionaryofvariablebindings(_voicechangebutton)];
[self addconstraints:voiceconstrainth];
nsarray *voiceconstraintv = [nslayoutconstraint constraintswithvisualformat:@ "v:|-8-[_voicechangebutton(30)]" options:0 metrics:0 views:nsdictionaryofvariablebindings(_voicechangebutton)];
[self addconstraints:voiceconstraintv];
//给morebutton添加约束
self.morebutton.translatesautoresizingmaskintoconstraints = no;
nsarray *morebuttonh = [nslayoutconstraint constraintswithvisualformat:@ "h:[_morebutton(30)]-5-|" options:0 metrics:0 views:nsdictionaryofvariablebindings(_morebutton)];
[self addconstraints:morebuttonh];
nsarray *morebuttonv = [nslayoutconstraint constraintswithvisualformat:@ "v:|-8-[_morebutton(30)]" options:0 metrics:0 views:nsdictionaryofvariablebindings(_morebutton)];
[self addconstraints:morebuttonv];
//给changekeyboardbutton添加约束
self.changekeyboardbutton.translatesautoresizingmaskintoconstraints = no;
nsarray *changekeyboardbuttonh = [nslayoutconstraint constraintswithvisualformat:@ "h:[_changekeyboardbutton(33)]-43-|" options:0 metrics:0 views:nsdictionaryofvariablebindings(_changekeyboardbutton)];
[self addconstraints:changekeyboardbuttonh];
nsarray *changekeyboardbuttonv = [nslayoutconstraint constraintswithvisualformat:@ "v:|-5-[_changekeyboardbutton(33)]" options:0 metrics:0 views:nsdictionaryofvariablebindings(_changekeyboardbutton)];
[self addconstraints:changekeyboardbuttonv];
//给文本框添加约束
self.sendtextview.translatesautoresizingmaskintoconstraints = no;
nsarray *sendtextviewconstrainth = [nslayoutconstraint constraintswithvisualformat:@ "h:|-45-[_sendtextview]-80-|" options:0 metrics:0 views:nsdictionaryofvariablebindings(_sendtextview)];
[self addconstraints:sendtextviewconstrainth];
nsarray *sendtextviewconstraintv = [nslayoutconstraint constraintswithvisualformat:@ "v:|-10-[_sendtextview]-10-|" options:0 metrics:0 views:nsdictionaryofvariablebindings(_sendtextview)];
[self addconstraints:sendtextviewconstraintv];
//语音发送按钮
self.sendvoicebutton.translatesautoresizingmaskintoconstraints = no;
nsarray *sendvoicebuttonconstrainth = [nslayoutconstraint constraintswithvisualformat:@ "h:|-50-[_sendvoicebutton]-90-|" options:0 metrics:0 views:nsdictionaryofvariablebindings(_sendvoicebutton)];
[self addconstraints:sendvoicebuttonconstrainth];
nsarray *sendvoicebuttonconstraintv = [nslayoutconstraint constraintswithvisualformat:@ "v:|-6-[_sendvoicebutton]-6-|" options:0 metrics:0 views:nsdictionaryofvariablebindings(_sendvoicebutton)];
[self addconstraints:sendvoicebuttonconstraintv];
}
|
5.因为我们要发送录音,所以对音频部分的初始化是少不了的,以下代码是对音频的初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
//录音部分初始化
-( void )audioinit
{
nserror * err = nil;
avaudiosession *audiosession = [avaudiosession sharedinstance];
[audiosession setcategory :avaudiosessioncategoryplayandrecord error:&err];
if (err){
nslog(@ "audiosession: %@ %d %@" , [err domain], [err code], [[err userinfo] description]);
return ;
}
[audiosession setactive:yes error:&err];
err = nil;
if (err){
nslog(@ "audiosession: %@ %d %@" , [err domain], [err code], [[err userinfo] description]);
return ;
}
//通过可变字典进行配置项的加载
nsmutabledictionary *setaudiodic = [[nsmutabledictionary alloc] init];
//设置录音格式(aac格式)
[setaudiodic setvalue:@(kaudioformatmpeg4aac) forkey:avformatidkey];
//设置录音采样率(hz) 如:avsampleratekey==8000/44100/96000(影响音频的质量)
[setaudiodic setvalue:@(44100) forkey:avsampleratekey];
//设置录音通道数1 or 2
[setaudiodic setvalue:@(1) forkey:avnumberofchannelskey];
//线性采样位数 8、16、24、32
[setaudiodic setvalue:@16 forkey:avlinearpcmbitdepthkey];
//录音的质量
[setaudiodic setvalue:@(avaudioqualityhigh) forkey:avencoderaudioqualitykey];
nsstring *strurl = [nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes) lastobject];
nsstring *filename = [nsstring stringwithformat:@ "%ld" , ( long )[[nsdate date] timeintervalsince1970]];
nsurl *url = [nsurl fileurlwithpath:[nsstring stringwithformat:@ "%@/%@.aac" , strurl, filename]];
_audioplayurl = url;
nserror *error;
//初始化
self.audiorecorder = [[avaudiorecorder alloc]initwithurl:url settings:setaudiodic error:&error];
//开启音量检测
self.audiorecorder.meteringenabled = yes;
self.audiorecorder.delegate = self;
}
|
6.添加键盘回收键done
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//给键盘添加done键
-( void ) adddone
{
//textview的键盘定制回收按钮
uitoolbar * toolbar = [[uitoolbar alloc]initwithframe:cgrectmake(0, 0, 320, 30)];
uibarbuttonitem * item1 = [[uibarbuttonitem alloc]initwithbarbuttonsystemitem:uibarbuttonsystemitemdone target:self action:@selector(tapdone:)];
uibarbuttonitem * item2 = [[uibarbuttonitem alloc]initwithbarbuttonsystemitem:uibarbuttonsystemitemflexiblespace target:nil action:nil];
uibarbuttonitem * item3 = [[uibarbuttonitem alloc]initwithbarbuttonsystemitem:uibarbuttonsystemitemflexiblespace target:nil action:nil];
toolbar.items = @[item2,item1,item3];
self.sendtextview.inputaccessoryview =toolbar;
}
|
三.编写控件的回调方法
控件添加好以后下面要添加触发控件要干的事情:
1.从最复杂的开始,长按发送录音的按钮时,会录音。松开收时会发送(在发送时要判断音频的时间,太小不允许发送)。录音时上滑取消录音(删除录音文件)。主要是给录音按钮加了一个longpress手势,根据手势的状态来做不同的事情。关于手势的内容请参考之前的博客:(ios开发之手势识别),下面是录音业务逻辑的实现(个人在coding的时候,感觉这一块是工具条中最复杂的部分),代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
//长按手势触发的方法
-( void )sendvoicebuttonlongpress:(id)sender
{
static int i = 1;
if ([sender iskindofclass:[uilongpressgesturerecognizer class ]]) {
uilongpressgesturerecognizer * longpress = sender;
//录音开始
if (longpress.state == uigesturerecognizerstatebegan)
{
i = 1;
[self.sendvoicebutton settitlecolor:[uicolor redcolor] forstate:uicontrolstatenormal];
//录音初始化
[self audioinit];
//创建录音文件,准备录音
if ([self.audiorecorder preparetorecord])
{
//开始
[self.audiorecorder record];
//设置定时检测音量变化
_timer = [nstimer scheduledtimerwithtimeinterval:0.05 target:self selector:@selector(detectionvoice) userinfo:nil repeats:yes];
}
}
//取消录音
if (longpress.state == uigesturerecognizerstatechanged)
{
cgpoint piont = [longpress locationinview:self];
nslog(@ "%f" ,piont.y);
if (piont.y < -20)
{
if (i == 1) {
[self.sendvoicebutton setbackgroundimage:[uiimage imagenamed:@ "chat_bottom_textfield.png" ] forstate:uicontrolstatenormal];
[self.sendvoicebutton settitlecolor:[uicolor blackcolor] forstate:uicontrolstatenormal];
//删除录制文件
[self.audiorecorder deleterecording];
[self.audiorecorder stop];
[_timer invalidate];
uialertview *alter = [[uialertview alloc] initwithtitle:@ "提示" message:@ "录音取消" delegate:nil cancelbuttontitle:@ "取消" otherbuttontitles: nil];
[alter show];
//去除图片用的
self.cancelblock(1);
i = 0;
}
}
}
if (longpress.state == uigesturerecognizerstateended) {
if (i == 1)
{
nslog(@ "录音结束" );
[self.sendvoicebutton setbackgroundimage:[uiimage imagenamed:@ "chat_bottom_textfield.png" ] forstate:uicontrolstatenormal];
[self.sendvoicebutton settitlecolor:[uicolor blackcolor] forstate:uicontrolstatenormal];
double ctime = self.audiorecorder.currenttime;
if ( ctime > 1)
{
//如果录制时间<2 不发送
nslog(@ "发出去" );
self.urlblock(self.audioplayurl);
}
else
{
//删除记录的文件
[self.audiorecorder deleterecording];
uialertview *alter = [[uialertview alloc] initwithtitle:@ "提示" message:@ "录音时间太短!" delegate:nil cancelbuttontitle:@ "取消" otherbuttontitles: nil];
[alter show];
self.cancelblock(1);
}
[self.audiorecorder stop];
[_timer invalidate];
}
}
}
}
|
2.下面的代码是检测音量的变化,用于根据音量变化图片,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
//录音的音量探测
- ( void )detectionvoice
{
[self.audiorecorder updatemeters]; //刷新音量数据
//获取音量的平均值 [recorder averagepowerforchannel:0];
//音量的最大值 [recorder peakpowerforchannel:0];
cgfloat lowpassresults = pow (10, (0.05 * [self.audiorecorder peakpowerforchannel:0]));
//把声音的音量传给调用者
self.volumeblock(lowpassresults);
}
|
3.轻击输入框时,切换到系统键盘,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
//轻击sendtext切换键盘
-( void )tapgesture:(uitapgesturerecognizer *) sender
{
if ([self.sendtextview.inputview isequal:self.functionview])
{
self.sendtextview.inputview = nil;
[self.changekeyboardbutton setimage:[uiimage imagenamed:@ "chat_bottom_smile_nor.png" ] forstate:uicontrolstatenormal];
[self.sendtextview reloadinputviews];
}
if (![self.sendtextview isfirstresponder])
{
[self.sendtextview becomefirstresponder];
}
}
|
4.通过输入框的文字多少改变toolview的高度,因为输入框的约束是加在toolview上的,所以需要把输入框的contentsize通过block传到toolview的调用者上,让toolview的父视图来改变toolview的高度,从而sendtextview的高度也会随着改变的,下面的代码是把contentsize交给父视图:代码如下:
1
2
3
4
5
6
7
|
//通过文字的多少改变toolview的高度
-( void )textviewdidchange:(uitextview *)textview
{
cgsize contentsize = self.sendtextview.contentsize;
self.sizeblock(contentsize);
}
|
效果如下,文字多时textview的高度也会增大:
5.点击最左边的按钮触发的事件(切换文本输入框和录音按钮),代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
//切换声音按键和文字输入框
-( void )tapvoicechangebutton:(uibutton *) sender
{
if (self.sendvoicebutton.hidden == yes)
{
self.sendtextview.hidden = yes;
self.sendvoicebutton.hidden = no;
[self.voicechangebutton setimage:[uiimage imagenamed:@ "chat_bottom_keyboard_nor.png" ] forstate:uicontrolstatenormal];
if ([self.sendtextview isfirstresponder]) {
[self.sendtextview resignfirstresponder];
}
}
else
{
self.sendtextview.hidden = no;
self.sendvoicebutton.hidden = yes;
[self.voicechangebutton setimage:[uiimage imagenamed:@ "chat_bottom_voice_press.png" ] forstate:uicontrolstatenormal];
if (![self.sendtextview isfirstresponder]) {
[self.sendtextview becomefirstresponder];
}
}
}
|
6.点击return发送文字(通过block回调传入到父视图上),代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//发送信息(点击return)
- ( bool )textview:(uitextview *)textview shouldchangetextinrange:(nsrange)range replacementtext:(nsstring *)text
{
if ([text isequaltostring:@ "\n" ])
{
//通过block回调把text的值传递到controller*
self.textblock(self.sendtextview.text);
self.sendtextview.text = @ "" ;
return no;
}
return yes;
}
|
7.录音按钮本身要做的事情(在longpress没有被触发时调用)代码如下:
1
2
3
4
5
6
7
8
|
//发送声音按钮回调的方法
-( void )tapsendvoicebutton:(uibutton *) sender
{
nslog(@ "sendvoicebutton" );
//点击发送按钮没有触发长按手势要做的事儿
uialertview *alter = [[uialertview alloc] initwithtitle:@ "提示" message:@ "按住录音" delegate:nil cancelbuttontitle:@ "取消" otherbuttontitles: nil];
[alter show];
}
|
8.调用表情键盘:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
//变成表情键盘
-( void )tapchangekeyboardbutton:(uibutton *) sender
{
if ([self.sendtextview.inputview isequal:self.functionview])
{
self.sendtextview.inputview = nil;
[self.changekeyboardbutton setimage:[uiimage imagenamed:@ "chat_bottom_smile_nor.png" ] forstate:uicontrolstatenormal];
[self.sendtextview reloadinputviews];
}
else
{
self.sendtextview.inputview = self.functionview;
[self.changekeyboardbutton setimage:[uiimage imagenamed:@ "chat_bottom_keyboard_nor.png" ] forstate:uicontrolstatenormal];
[self.sendtextview reloadinputviews];
}
if (![self.sendtextview isfirstresponder])
{
[self.sendtextview becomefirstresponder];
}
if (self.sendtextview.hidden == yes) {
self.sendtextview.hidden = no;
self.sendvoicebutton.hidden = yes;
[self.voicechangebutton setimage:[uiimage imagenamed:@ "chat_bottom_voice_press.png" ] forstate:uicontrolstatenormal];
}
}
|
以上就是toolview的所有封装代码,至于在controller中如何使用他来发送消息,如何定义聊天cell,如何处理录音文件,聊天时的气泡是如何实现的等功能,在以后的文章中会继续讲解,希望大家继续关注。