ios弹幕高效加载实现方式实例代码

2025-05-29 0 27

看直播的童鞋们应该会经常看到满屏幕的滚动弹幕,看到密密麻麻的弹幕第一印象就是怎么样高效加载来避免卡顿,弹幕组成部分包含用户头像、用户昵称、弹幕的内容、表情等,本文介绍的实现原理就是把这几部分绘制成一张图片,然后通过定时器移动弹幕图片,当图片不在屏幕范围内即销毁。

先看下效果

ios弹幕高效加载实现方式实例代码

ios弹幕高效加载实现方式实例代码

下面我会详细介绍下实现原理

1 .获取弹幕数据来源,因为我是模拟生成弹幕弹幕的数据存放在工程里的plist文件中

ios弹幕高效加载实现方式实例代码

emotions存放这条弹幕的表情,type表示是否是自己发的,text表示弹幕内容,username表示用户昵称。取出plist文件的数据并转换成model。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14
#pragma mark - 获取数据源

- (void)loaddata{

// 获取plist全路径

nsstring *filepath = [[nsbundle mainbundle] pathforresource:@"barrage.plist" oftype:nil];

// 从指定的路径中加载数据

nsarray *array = [nsarray arraywithcontentsoffile:filepath];

// 遍历数组

for (nsdictionary *dict in array) {

// 字典转模型

bamodle *barragem = [bamodle barragewithdict:dict];

[self.danmus addobject:barragem];

}

}

2 .根据模型生成弹幕图片,通过点击屏幕生成模型,根据模型绘制图片。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15
#pragma mark - 触摸屏幕响应事件

- (void)touchesbegan:(nsset<uitouch *> *)touches withevent:(uievent *)event{

// 获得一个随机整数

nsinteger index = arc4random_uniform((u_int32_t)self.danmus.count);

// 获得一个随机模型

bamodle *danmu = self.danmus[index];

// 根据模型生成图片

baimage *image = [self.danmuview imagewithbarrage:danmu];

// 调整弹幕加载区域

image.x = self.view.bounds.size.width;

image.y = arc4random_uniform(self.danmuview.bounds.size.height - image.size.height);

// 把图片加到弹幕view上

[self.danmuview addimage:image];

}

下面是具体绘制弹幕图片过程,我先简单介绍下,首先在绘图之前要确定上下文的尺寸,相当于画板的大小,画板的长 = 头像的长 + 昵称的长 + 内容的长 + 表情的长 * 表情个数 + 间距。然后就是分别绘制背景图片,用户昵称,内容和表情,最后返回一张图片。

此处有两点需要注意:

1.由于头像是矩形,想显示成圆形,要先画一个圆,并设置超出圆形的部分要裁剪,再绘制头像。

2.由于上面设置超出圆形的部分要裁剪,那即将要绘制背景岂不是要被裁剪,所以在绘制圆形区域上一句执行了cgcontextsavegstate(ctx)表示复制了一份画板(上下文)存到栈里,在绘制背景图片之前执行cgcontextrestoregstate(ctx),表示用之前保存的画板替换当前的,因为之前保存的画板没有设置超出圆形区域要裁剪的需求,当然替换当前的画板,会把当前画板上的绘图也copy过去。

?

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
#pragma mark - 绘制弹幕图片

- (baimage *)imagewithbarrage:(bamodle *)danmu{

// 开启绘图上下文

//

uifont *font = [uifont systemfontofsize:13];

// 头像

cgfloat iconh = 30;

cgfloat iconw = iconh;

// 间距

cgfloat marginx = 5;

// 表情的尺寸

cgfloat emotionw = 25;

cgfloat emotionh = emotionw;

// 计算用户名占据的区域

cgsize namesize = [danmu.username boundingrectwithsize:cgsizemake(maxfloat, maxfloat) options:nsstringdrawinguseslinefragmentorigin attributes:@{nsfontattributename:font} context:nil].size;

// 计算内容占据的区域

cgsize textsize = [danmu.text boundingrectwithsize:cgsizemake(maxfloat, maxfloat) options:nsstringdrawinguseslinefragmentorigin attributes:@{nsfontattributename:font} context:nil].size;

// 位图上下文的尺寸

cgfloat contenth = iconh;

cgfloat contentw = iconw + 4 * marginx + namesize.width + textsize.width + danmu.emotions.count * emotionh;

cgsize contextsize = cgsizemake(contentw, contenth);

uigraphicsbeginimagecontextwithoptions(contextsize, no, 0.0);

// 获得位图上下文

cgcontextref ctx = uigraphicsgetcurrentcontext();

// 将上下文保存到栈中

cgcontextsavegstate(ctx);

// 1.绘制圆形区域

cgrect iconframe = cgrectmake(0, 0, iconw, iconh);

// 绘制头像圆形

cgcontextaddellipseinrect(ctx, iconframe);

// 超出圆形的要裁剪

cgcontextclip(ctx);

// 2.绘制头像

uiimage *icon = danmu.type ? [uiimage imagenamed:@"headimage_1"]:[uiimage imagenamed:@"headimage_2"];

[icon drawinrect:iconframe];

// 将上下文出栈替换当前上下文

cgcontextrestoregstate(ctx);

// 3.绘制背景图片

cgfloat bgx = iconw + marginx;

cgfloat bgy = 0;

cgfloat bgw = contentw - bgx;

cgfloat bgh = contenth;

danmu.type ? [[uicolor orangecolor] set]:[[uicolor whitecolor] set];

[[uibezierpath bezierpathwithroundedrect:cgrectmake(bgx, bgy, bgw, bgh) cornerradius:20.0] fill];

// 4.绘制用户名

cgfloat namex = bgx + marginx;

cgfloat namey = (contenth - namesize.height) * 0.5;

[danmu.username drawatpoint:cgpointmake(namex, namey) withattributes:@{nsattachmentattributename:font,nsforegroundcolorattributename:danmu.type == no ? [uicolor orangecolor]:[uicolor blackcolor]}];

// 5.绘制内容

cgfloat textx = namex + namesize.width + marginx;

cgfloat texty = namey;

[danmu.text drawatpoint:cgpointmake(textx, texty) withattributes:@{nsattachmentattributename:font,nsforegroundcolorattributename:danmu.type == no ? [uicolor blackcolor]:[uicolor whitecolor]}];

// 6.绘制表情

__block cgfloat emotionx = textx + textsize.width;

cgfloat emotiony = (contenth - emotionh) * 0.5;

[danmu.emotions enumerateobjectsusingblock:^(nsstring *emotionname, nsuinteger idx, bool * _nonnull stop) {

// 加载表情图片

uiimage *emotion = [uiimage imagenamed:emotionname];

[emotion drawinrect:cgrectmake(emotionx, emotiony, emotionw, emotionh)];

// 修改emotionx

emotionx += emotionw;

}];

// 从位图上下文中获得绘制好的图片

uiimage *image = uigraphicsgetimagefromcurrentimagecontext();

return [[baimage alloc] initwithcgimage:image.cgimage scale:[uiscreen mainscreen].scale orientation:uiimageorientationup];

}

3 .开启绘图定时器,回调方法是setneedsdisplay,这样就会执行- (void)drawrect:(cgrect)rect每次修改image.x(由于uiimage没有x、y属性,所以写了个类拓展baimage),滚动不在屏幕范围内的会销毁

?

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
#pragma mark - 添加定时器

- (void)addtimer{

if (self.link) {

return;

}

// 每秒执行60次回调

cadisplaylink *link = [cadisplaylink displaylinkwithtarget:self selector:@selector(setneedsdisplay)];

// 将定时器添加到runloop

[link addtorunloop:[nsrunloop currentrunloop] formode:nsrunloopcommonmodes];

self.link = link;

}

#pragma mark - 绘制移动

- (void)drawrect:(cgrect)rect{

for (baimage *image in self.imagearray) {

image.x -= 3;

// 绘制图片

[image drawatpoint:cgpointmake(image.x, image.y)];

// 判断图片是否超出屏幕

if (image.x + image.size.width < 0) {

[self.deleteimagearray addobject:image];

}

}

// 移除超过屏幕的弹幕

for (baimage *image in self.deleteimagearray) {

[self.imagearray removeobject:image];

}

[self.deleteimagearray removeallobjects];

}

最后附上代码地址:barragedemo.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持快网idc。

收藏 (0) 打赏

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

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

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

快网idc优惠网 建站教程 ios弹幕高效加载实现方式实例代码 https://www.kuaiidc.com/91013.html

相关文章

发表评论
暂无评论