在B站或者其他视频网站看视频时,常常会打开弹幕效果,边看节目边看大家的吐槽。弹幕看起来很有意思,今天我们就来实现一个简单的弹幕效果。

从直观上,弹幕效果就是在一个ViewGroup上增加一些View,然后让这些View移动起来。所以,整体的实现思路大概是这样的:

1、定义一个RelativeLayout,在里面动态添加TextView。

2、这些TextView的字体大小、颜色、移动速度、初始位置都是随机的。

3、将TextView添加到RelativeLayout的右边缘,每隔一段时间添加一个。

4、对每个TextView做平移动画,使得TextView从右向左移动。

5、当TextView从左边移动出屏幕,将TextView从RelativeLayout中移除。

有了思路下面就来看具体的代码。

首先定义BarrageItem,用来存储每一个弹幕项的相关信息,包括字体内容、字体大小颜色、移动速度、垂直方向的位置、字体占据的宽度等。

[java] view plaincopyprint?
  1. public class BarrageItem {
  2. public TextView textView;
  3. public int textColor;
  4. public String text;
  5. public int textSize;
  6. public int moveSpeed;//移动速度
  7. public int verticalPos;//垂直方向显示的位置
  8. public int textMeasuredWidth;//字体显示占据的宽度
  9. }

public class BarrageItem {public TextView textView;public int textColor;public String text;public int textSize;public int moveSpeed;//移动速度public int verticalPos;//垂直方向显示的位置public int textMeasuredWidth;//字体显示占据的宽度
}

然后定义BarrageView,由于弹幕的字体颜色大小和移动速度都是随机的,需要定义最大最小值来限定它们的范围,然后通过产生随机数来设置它们在这个范围内的值。另外还需要定义弹幕的文本内容,这里是直接写死的一些固定值。

[java] view plaincopyprint?
  1. private Context mContext;
  2. private BarrageHandler mHandler = new BarrageHandler();
  3. private Random random = new Random(System.currentTimeMillis());
  4. private static final long BARRAGE_GAP_MIN_DURATION = 1000;//两个弹幕的最小间隔时间
  5. private static final long BARRAGE_GAP_MAX_DURATION = 2000;//两个弹幕的最大间隔时间
  6. private int maxSpeed = 10000;//速度,ms
  7. private int minSpeed = 5000;//速度,ms
  8. private int maxSize = 30;//文字大小,dp
  9. private int minSize = 15;//文字大小,dp
  10. private int totalHeight = 0;
  11. private int lineHeight = 0;//每一行弹幕的高度
  12. private int totalLine = 0;//弹幕的行数
  13. private String[] itemText = {“是否需要帮忙”, “what are you 弄啥来”, “哈哈哈哈哈哈哈”, “抢占沙发。。。。。。”, “************”, “是否需要帮忙”,“我不会轻易的狗带”, “嘿嘿”, “这是我见过的最长长长长长长长长长长长的评论”};
  14. private int textCount;
  15. //    private List<BarrageItem> itemList = new ArrayList<BarrageItem>();
  16. public BarrageView(Context context) {
  17. this(context, null);
  18. }
  19. public BarrageView(Context context, AttributeSet attrs) {
  20. this(context, attrs, 0);
  21. }
  22. public BarrageView(Context context, AttributeSet attrs, int defStyleAttr) {
  23. super(context, attrs, defStyleAttr);
  24. mContext = context;
  25. init();
  26. }

    private Context mContext;private BarrageHandler mHandler = new BarrageHandler();private Random random = new Random(System.currentTimeMillis());private static final long BARRAGE_GAP_MIN_DURATION = 1000;//两个弹幕的最小间隔时间private static final long BARRAGE_GAP_MAX_DURATION = 2000;//两个弹幕的最大间隔时间private int maxSpeed = 10000;//速度,msprivate int minSpeed = 5000;//速度,msprivate int maxSize = 30;//文字大小,dpprivate int minSize = 15;//文字大小,dpprivate int totalHeight = 0;private int lineHeight = 0;//每一行弹幕的高度private int totalLine = 0;//弹幕的行数private String[] itemText = {"是否需要帮忙", "what are you 弄啥来", "哈哈哈哈哈哈哈", "抢占沙发。。。。。。", "************", "是否需要帮忙","我不会轻易的狗带", "嘿嘿", "这是我见过的最长长长长长长长长长长长的评论"};private int textCount;
//    private List<BarrageItem> itemList = new ArrayList<BarrageItem>();public BarrageView(Context context) {this(context, null);}public BarrageView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public BarrageView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);mContext = context;init();}

如果弹幕显示的垂直位置是随机的,就会出现垂直方向上弹幕重叠的情况,所以需要根据高度对垂直方向按照弹幕高度的最大值等分,然后让弹幕在这些指定的垂直位置随机分布。这个值在onWindowFocusChanged里计算,因为在这个方法中通过View的getMeasuredHeight()得到的高度不为空。

[java] view plaincopyprint?
  1. @Override
  2. public void onWindowFocusChanged(boolean hasWindowFocus) {
  3. super.onWindowFocusChanged(hasWindowFocus);
  4. totalHeight = getMeasuredHeight();
  5. lineHeight = getLineHeight();
  6. totalLine = totalHeight / lineHeight;
  7. }

    @Overridepublic void onWindowFocusChanged(boolean hasWindowFocus) {super.onWindowFocusChanged(hasWindowFocus);totalHeight = getMeasuredHeight();lineHeight = getLineHeight();totalLine = totalHeight / lineHeight;}

通过Handler的sendEmptyMessageDelayed每隔随机的时间产生一个弹幕项。下面的代码设置弹幕项的属性。

[java] view plaincopyprint?
  1. class BarrageHandler extends Handler {
  2. @Override
  3. public void handleMessage(Message msg) {
  4. super.handleMessage(msg);
  5. generateItem();
  6. //每个弹幕产生的间隔时间随机
  7. int duration = (int) ((BARRAGE_GAP_MAX_DURATION - BARRAGE_GAP_MIN_DURATION) * Math.random());
  8. this.sendEmptyMessageDelayed(0, duration);
  9. }
  10. }
  11. private void generateItem() {
  12. BarrageItem item = new BarrageItem();
  13. String tx = itemText[(int) (Math.random() * textCount)];
  14. int sz = (int) (minSize + (maxSize - minSize) * Math.random());
  15. item.textView = new TextView(mContext);
  16. item.textView.setText(tx);
  17. item.textView.setTextSize(sz);
  18. item.textView.setTextColor(Color.rgb(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
  19. item.textMeasuredWidth = (int) getTextWidth(item, tx, sz);
  20. item.moveSpeed = (int) (minSpeed + (maxSpeed - minSpeed) * Math.random());
  21. if (totalLine == 0) {
  22. totalHeight = getMeasuredHeight();
  23. lineHeight = getLineHeight();
  24. totalLine = totalHeight / lineHeight;
  25. }
  26. item.verticalPos = random.nextInt(totalLine) * lineHeight;
  27. showBarrageItem(item);
  28. }

    class BarrageHandler extends Handler {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);generateItem();//每个弹幕产生的间隔时间随机int duration = (int) ((BARRAGE_GAP_MAX_DURATION - BARRAGE_GAP_MIN_DURATION) * Math.random());this.sendEmptyMessageDelayed(0, duration);}}private void generateItem() {BarrageItem item = new BarrageItem();String tx = itemText[(int) (Math.random() * textCount)];int sz = (int) (minSize + (maxSize - minSize) * Math.random());item.textView = new TextView(mContext);item.textView.setText(tx);item.textView.setTextSize(sz);item.textView.setTextColor(Color.rgb(random.nextInt(256), random.nextInt(256), random.nextInt(256)));item.textMeasuredWidth = (int) getTextWidth(item, tx, sz);item.moveSpeed = (int) (minSpeed + (maxSpeed - minSpeed) * Math.random());if (totalLine == 0) {totalHeight = getMeasuredHeight();lineHeight = getLineHeight();totalLine = totalHeight / lineHeight;}item.verticalPos = random.nextInt(totalLine) * lineHeight;showBarrageItem(item);}

将每一个弹幕项添加到视图上,并给View添加一个TranslateAnimation动画,当动画结束时,将View从视图上移除。

[java] view plaincopyprint?
  1. private void showBarrageItem(final BarrageItem item) {
  2. int leftMargin = this.getWidth();
  3. LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
  4. params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
  5. params.topMargin = item.verticalPos;
  6. this.addView(item.textView, params);
  7. Animation anim = generateTranslateAnim(item, leftMargin);
  8. anim.setAnimationListener(new Animation.AnimationListener() {
  9. @Override
  10. public void onAnimationStart(Animation animation) {
  11. }
  12. @Override
  13. public void onAnimationEnd(Animation animation) {
  14. item.textView.clearAnimation();
  15. BarrageView.this.removeView(item.textView);
  16. }
  17. @Override
  18. public void onAnimationRepeat(Animation animation) {
  19. }
  20. });
  21. item.textView.startAnimation(anim);
  22. }
  23. private TranslateAnimation generateTranslateAnim(BarrageItem item, int leftMargin) {
  24. TranslateAnimation anim = new TranslateAnimation(leftMargin, -item.textMeasuredWidth, 0, 0);
  25. anim.setDuration(item.moveSpeed);
  26. anim.setInterpolator(new AccelerateDecelerateInterpolator());
  27. anim.setFillAfter(true);
  28. return anim;
  29. }

private void showBarrageItem(final BarrageItem item) {int leftMargin = this.getWidth();LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);params.addRule(RelativeLayout.ALIGN_PARENT_TOP);params.topMargin = item.verticalPos;this.addView(item.textView, params);Animation anim = generateTranslateAnim(item, leftMargin);anim.setAnimationListener(new Animation.AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {item.textView.clearAnimation();BarrageView.this.removeView(item.textView);}@Overridepublic void onAnimationRepeat(Animation animation) {}});item.textView.startAnimation(anim);}private TranslateAnimation generateTranslateAnim(BarrageItem item, int leftMargin) {TranslateAnimation anim = new TranslateAnimation(leftMargin, -item.textMeasuredWidth, 0, 0);anim.setDuration(item.moveSpeed);anim.setInterpolator(new AccelerateDecelerateInterpolator());anim.setFillAfter(true);return anim;}

这样就完成了弹幕的功能,实现原理并不复杂。可以根据具体的需求来增加更多的控制,如控制每一行弹幕不重复,控制弹幕移动的Interpolator产生不同的滑动效果等等。

源码下载

Android直播中弹幕效果实现相关推荐

  1. Android 直播中弹幕、带货和键盘的交互

    mAttachInfo.mTreeObserver.dispatchOnGlobalLayout(); } 当一个 Activity或者是Dialog 这样的 Window对添加的布局完成测量和布局后 ...

  2. Android 直播中弹幕、带货和键盘的交互,android视频开发框架

    // 改变当前布局的大小来适应键盘,会触发 GlobalLayoutListener 回调,这个配置就非常适合做微信这种 IM 聊天界面 android:windowSoftInputMode=&qu ...

  3. Android弹幕功能实现,模仿斗鱼直播的弹幕效果

    转载请注明出处:http://blog.csdn.net/sinyu890807/article/details/51933728 本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭 ...

  4. Android仿斗鱼直播的弹幕效果

    今天,我就带着大家一起来实现一个简单的Android端弹幕效果. 分析 首先我们来看一下斗鱼上的弹幕效果,如下图所示: 这是一个Dota2游戏直播的界面,我们可以看到,在游戏界面的上方有很多的弹幕,看 ...

  5. Android弹幕功能实现,模仿斗鱼直播的弹幕效果,跪了

    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_ ...

  6. 仿斗鱼直播的弹幕效果实现

    今日科技快讯 这两天最大的科技新闻莫过于神舟十一号升空了.10月17日上午7点30分,神舟十一号于酒泉卫星发射中心顺利发射,航天员由景海鹏和陈冬二人组成.神舟十一号将会先和天宫二号完成对接,形成组合体 ...

  7. Flutter直播间弹幕效果实现

    主要实现直播间弹幕的布局,弹幕滚动,弹幕淡出效果,去除ListView的水波纹 1.danmu.dart布局的实现 (1)使用Text.rich组件完成弹幕文字部分的布局,TextSpan的child ...

  8. android 如何实现弹幕,Android简单实现弹幕效果

    本文实例为大家分享了Android实现弹幕效果的具体代码,供大家参考,具体内容如下 首先分析一下,他是由三层布局来共同完成的,第一层视频布局,第二层字幕布局,第三层输入框布局,要想让这三个布局在同一页 ...

  9. 微信Android客户端中表情雨效果的实现

    微信android客户端中的表情雨效果在聊天中生动活泼,具体会出现特殊效果的词有恭喜发财.年年有余.想你了.生日快乐.么么哒等等,随着节日来临会有更新词库及图片内容出现.具体效果如下图: 现就其实现过 ...

最新文章

  1. 转:查看系统是64位还是32位
  2. 罗杰·科恩伯格:基础科学——人类进步的希望
  3. Run Android on Your Netbook or Desktop
  4. Challenge: Machine Learning Basics
  5. BST-V51开发板用c语言,小代码 向原文学习 BST 简单的C语言版本
  6. div显示图片_图片按照百分比显示部分,不变形
  7. Tomcat5.5链接Oracle、DB2、MySQL数据源实现JSP下拉框的填充
  8. linux samba
  9. bp神经网络算法原理 Levenberg Marquardt
  10. VC 读取usb相机
  11. 杭电ACM 2000-2099 100道题 详细解题报告出炉
  12. 牛客网 2018年全国多校算法寒假训练营练习比赛(第四场)
  13. 福禄克FLUKE TIX650红外热像仪3.5英寸高像素大屏
  14. 傲游 android 2.3,傲游浏览器安卓版-傲游浏览器手机版v5.2.3.3256-3454手机软件
  15. mac 在连接wifi时出现 无互联网连接 的警告,叹号
  16. 类别不均衡问题之loss大集合:focal loss, GHM loss, dice loss 等等
  17. Unity记录3.1-地图-TileMap简单使用、鼠标拖动放置Tile
  18. 前2个月我国外贸进出口5919.9亿美元,下降11%,贸易逆差70.9亿美元
  19. 前端三剑客入门学习笔记之HTML
  20. sisoftware java测试_SiSoftware Sandra测试及全文总结_内存硬盘评测-中关村在线

热门文章

  1. mac蓝牙连接有问题要怎么处理呢?
  2. luogu3933 Chtholly Nota Seniorious
  3. 初中计算机初识word教学设计,《初识Word》教学设计
  4. [声纹识别]基于MFCC的声纹识别算法
  5. Go 语言 app.conf配置文件
  6. Android 撕开衣服解析
  7. 华三模拟器实现DHCP获取地址
  8. 阿里云邮箱域名解析设置要求
  9. jadx工具介绍及使用
  10. 弘辽科技:如何写出自带流量的标题