1、Android 弹幕实现:基于 B 站弹幕开源系统( 1)Android 弹幕实现:基于 B 站弹幕开源系统( 1)如今的视频播放,流行在视频上飘弹幕。这里面做的相对比较成熟、稳定、使用量较多的弹幕系统,当推 B 站的弹幕系统, B 站的弹幕系统已经作为开源项目在 github 上,其项目地址:https:/ 以 B 站开源的弹幕项目为基础,现给出一个简单的例子,实现发送简单的文本弹幕。第一步,首先要在 Android 的 build.gradle 文件中引入 B 站的项目:plain view plain copy1. repositories 2. jcenter() 3. 4. 5. 6
2、. dependencies 7. 8. compile com.github.ctiao:DanmakuFlameMaster:0.7.3 9. compile com.github.ctiao:ndkbitmap-armv7a:0.7.3 10. 11. 第二步,写一个布局文件,引入 B 站的弹幕 view:html view plain copy1. 2. 6. 7. 12. 13. 18. 19. 24. 25. 30. 31. 36. 37. 41. 42. 第三步,写上层 Java 代码(该处 java 代码改造自 B 站弹幕 github 上的 demo 代码):java vie
3、w plain copy1. package zhangphil.danmaku; 2. 3. import android.app.Activity; 4. import android.graphics.Color; 5. import android.os.Bundle; 6. import android.util.Log; 7. import android.view.View; 8. import android.widget.Button; 9. 10. import java.util.HashMap; 11. 12. import master.flame.danmaku.d
4、anmaku.model.BaseDanmaku; 13. import master.flame.danmaku.danmaku.model.DanmakuTimer; 14. import master.flame.danmaku.danmaku.model.IDisplayer; 15. import master.flame.danmaku.danmaku.model.android.DanmakuContext; 16. import master.flame.danmaku.ui.widget.DanmakuView; 17. 18. public class MainActivi
5、ty extends Activity 19. 20. private DanmakuView mDanmakuView; 21. private DanmakuContext mContext; 22. 23. private AcFunDanmakuParser mParser; 24. 25. Override 26. protected void onCreate(Bundle savedInstanceState) 27. super.onCreate(savedInstanceState); 28. setContentView(R.layout.activity_main); 2
6、9. 30. mDanmakuView = (DanmakuView) findViewById(R.id.danmakuView); 31. 32. Button show = (Button) findViewById(R.id.show); 33. Button hide = (Button) findViewById(R.id.hide); 34. Button sendText = (Button) findViewById(R.id.sendText); 35. Button pause = (Button) findViewById(R.id.pause); 36. Button
7、 resume = (Button) findViewById(R.id.resume); 37. 38. show.setOnClickListener(new View.OnClickListener() 39. Override 40. public void onClick(View v) 41. mDanmakuView.show(); 42. 43. ); 44. 45. hide.setOnClickListener(new View.OnClickListener() 46. Override 47. public void onClick(View v) 48. mDanma
8、kuView.hide(); 49. 50. ); 51. 52. sendText.setOnClickListener(new View.OnClickListener() 53. Override 54. public void onClick(View v) 55. /每点击一次按钮发送一条弹幕 56. sendTextMessage(); 57. 58. ); 59. 60. pause.setOnClickListener(new View.OnClickListener() 61. Override 62. public void onClick(View v) 63. mDan
9、makuView.pause(); 64. 65. ); 66. 67. resume.setOnClickListener(new View.OnClickListener() 68. Override 69. public void onClick(View v) 70. mDanmakuView.resume(); 71. 72. ); 73. 74. 75. init(); 76. 77. 78. private void init() 79. mContext = DanmakuContext.create(); 80. 81. / 设置最大显示行数 82. HashMap maxL
10、inesPair = new HashMap(); 87. overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_RL, true); 88. overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_TOP, true); 89. 90. mContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN, 10) /描边的厚度 91. .setDuplicateMergingEnabled(false) 92. .setScrollSpeedFactor(1.2
11、f) /弹幕的速度。注意!此值越小,速度越快!值越大,速度越慢。/ by phil 93. .setScaleTextSize(1.2f) /缩放的值 94. /.setCacheStuffer(new SpannedCacheStuffer(), mCacheStufferAdapter) / 图文混排使用 SpannedCacheStuffer 95. / .setCacheStuffer(new BackgroundCacheStuffer() / 绘制背景使用BackgroundCacheStuffer 96. .setMaximumLines(maxLinesPair) 97. .p
12、reventOverlapping(overlappingEnablePair); 98. 99. mParser = new AcFunDanmakuParser(); 100. mDanmakuView.prepare(mParser, mContext); 101. 102. /mDanmakuView.showFPS(true); 103. mDanmakuView.enableDanmakuDrawingCache(true); 104. 105. if (mDanmakuView != null) 106. mDanmakuView.setCallback(new master.f
13、lame.danmaku.controller.DrawHandler.Callback() 107. Override 108. public void updateTimer(DanmakuTimer timer) 109. 110. 111. Override 112. public void drawingFinished() 113. 114. 115. 116. Override 117. public void danmakuShown(BaseDanmaku danmaku) 118. Log.d(“弹幕文本“, “danmakuShown text=“ + danmaku.t
14、ext);119. 120. 121. Override 122. public void prepared() 123. mDanmakuView.start(); 124. 125. ); 126. 127. 128. 129. private void sendTextMessage() 130. addDanmaku(true); 131. 132. 133. private void addDanmaku(boolean islive) 134. BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanm
15、aku.TYPE_SCROLL_RL); 135. if (danmaku = null | mDanmakuView = null) 136. return; 137. 138. 139. danmaku.text = “zhangphil csdn :“ + System.currentTimeMillis(); 140. danmaku.padding = 5; 141. danmaku.priority = 0; / 可能会被各种过滤器过滤并隐藏显示 142. danmaku.isLive = islive; 143. danmaku.setTime(mDanmakuView.getC
16、urrentTime() + 1200); 144. danmaku.textSize = 20f * (mParser.getDisplayer().getDensity() -0.6f); /文本弹幕字体大小 145. danmaku.textColor = getRandomColor(); /文本的颜色 146. danmaku.textShadowColor = getRandomColor(); /文本弹幕描边的颜色 147. /danmaku.underlineColor = Color.DKGRAY; /文本弹幕下划线的颜色 148. danmaku.borderColor =
17、 getRandomColor(); /边框的颜色 149. 150. mDanmakuView.addDanmaku(danmaku); 151. 152. 153. Override 154. protected void onPause() 155. super.onPause(); 156. if (mDanmakuView != null 158. 159. 160. 161. Override 162. protected void onResume() 163. super.onResume(); 164. if (mDanmakuView != null 166. 167. 1
18、68. 169. Override 170. protected void onDestroy() 171. super.onDestroy(); 172. if (mDanmakuView != null) 173. / dont forget release! 174. mDanmakuView.release(); 175. mDanmakuView = null; 176. 177. 178. 179. /* 180. * 从一系列颜色中随机选择一种颜色 181. * 182. * return 183. */ 184. private int getRandomColor() 185
19、. int colors = Color.RED, Color.YELLOW, Color.BLUE, Color.GREEN, Color.CYAN, Color.BLACK, Color.DKGRAY; 186. int i = (int) (Math.random() * 10) % colors.length; 187. return colorsi; 188. 189. 代码运行结果如图:需要特别注意的是本例使用了一个叫做 AcFunDanmakuParser 的弹幕 parser,这个解析器得自己写,自己基于 json 数据格式实现。该类写好基本就可以拿来稳定使用,现给出AcFun
20、DanmakuParser 的全部源代码:java view plain copy1. package zhangphil.danmaku; 2. 3. import org.json.JSONArray; 4. import org.json.JSONException; 5. import org.json.JSONObject; 6. 7. import master.flame.danmaku.danmaku.model.BaseDanmaku; 8. import master.flame.danmaku.danmaku.model.android.Danmakus; 9. impo
21、rt master.flame.danmaku.danmaku.parser.BaseDanmakuParser; 10. import master.flame.danmaku.danmaku.parser.android.JSONSource; 11. import master.flame.danmaku.danmaku.util.DanmakuUtils; 12. 13. /* 14. * Created by phil on 2017/3/29. 15. */ 16. 17. public class AcFunDanmakuParser extends BaseDanmakuPar
22、ser 18. 19. public AcFunDanmakuParser() 20. 21. 22. 23. public Danmakus parse() 24. if (this.mDataSource != null 26. return this.doParse(jsonSource.data(); 27. else 28. return new Danmakus(); 29. 30. 31. 32. private Danmakus doParse(JSONArray danmakuListData) 33. Danmakus danmakus = new Danmakus();
23、34. if (danmakuListData != null i 0) 63. int type = Integer.parseInt(values2); 64. if (type != 7) 65. long time = (long) (Float.parseFloat(values0) * 1000.0F); 66. int color = Integer.parseInt(values1) | -16777216; 67. float textSize = Float.parseFloat(values3); 68. BaseDanmaku item = this.mContext.
24、mDanmakuFactory.createDanmaku(type, this.mContext); 69. if (item != null) 70. item.setTime(time); 71. item.textSize = textSize * (this.mDispDensity - 0.6F); 72. item.textColor = color; 73. item.textShadowColor = color = -16777216 ? -1 : -16777216; 74. DanmakuUtils.fillText(item, jsonObject.optString(“m“, “); 75. item.index = i; 76. item.setTimer(this.mTimer); 77. danmakus.addItem(item); 78. 79. 80. 81. catch (JSONException var13) 82. 83. catch (NumberFormatException var14) 84. 85. 86. 87. 88. return danmakus; 89. else 90. return danmakus; 91. 92. 93.