iOS开发之微信聊天工具栏的封装

2025-05-29 0 78

微信大家基本上都用过,今天要做的就是微信的聊天工具条。聊天工具条还是比较复杂的,其中包括发送表情,发送文字,发送图片,发送声音,拍照等等功能,下面给出发送录音,文字,表情的代码,其他的和这几样类似。还是那句话百字不如一图,先来几张效果图吧。

iOS开发之微信聊天工具栏的封装

在封装聊天工具条的的时候表情键盘是之前封装好的,所以拿过来就可以用的啦。因为不管是工具条还是表情键盘都是用约束来控件大小的,所以横屏也是没问题的,在大屏手机上也是没问题的。下面将会一步步讲解如何封装下面的聊天工具条。主要是对工具条的封装,表情键盘在这就不做讲解了。
一、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的高度也会增大:

iOS开发之微信聊天工具栏的封装

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,如何处理录音文件,聊天时的气泡是如何实现的等功能,在以后的文章中会继续讲解,希望大家继续关注。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 iOS开发之微信聊天工具栏的封装 https://www.kuaiidc.com/93623.html

相关文章

发表评论
暂无评论