教你一步步实现bibibi弹幕功能。
在bibibi推出弹幕功能,我也爱上了边看视频边看吐槽了,现在让我们也来实现这一个功能吧。
首先我们要整理一下思绪我们大概需要实现哪个细节板块呢。
我们最直观的看来,弹幕就是总右往左出现到消失。我们要实现这个动画,弹幕的大小,颜色,出现方式,加速,弹幕的不重叠(这个我想了好久还没有实现,有实现方法可以联系下我)。
我们先来了解一下等会程序里面会用到的相关知识点,等会看代码会更轻松一点。
/*getHeight跟getMeasureHeight的区别* 实际上在当屏幕可以包裹内容的时候,他们的值相等,只有当view超出屏幕后,才能看出他们的区别:* getMeasuredHeight()是实际View的大小,与屏幕无关,而getHeight的大小此时则是屏幕的大小。* 当超出屏幕后, getMeasuredHeight() 等于 getHeight()加上屏幕之外没有显示的大小 * * */
/Activity生命周期中,onStart, onResume, onCreate都不是真正visible的时间点,真正的visible时间点是onWindowFocusChanged()函数被执行时。//当你屏幕的焦点发生变化时候,想要操作什么也完全可以在这个方法里面执行// Interpolator 被用来修饰动画效果,定义动画的变化率,可以使存在的动画效果accelerated(加速),decelerated(减速),repeated(重复),bounced(弹跳)等。/** AccelerateDecelerateInterpolator 在动画开始与结束的地方速率改变比较慢,在中间的时候加速AccelerateInterpolator 在动画开始的地方速率改变比较慢,然后开始加速AnticipateInterpolator 开始的时候向后然后向前甩AnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值BounceInterpolator 动画结束的时候弹起CycleInterpolator 动画循环播放特定的次数,速率改变沿着正弦曲线DecelerateInterpolator 在动画开始的地方快然后慢LinearInterpolator 以常量速率改变OvershootInterpolator 向前甩一定值后再回到原来位置
* fillBefore是指动画结束时画面停留在此动画的第一帧;fillAfter是指动画结束是画面停留在此动画的最后一帧。Java代码设置如下:/*****动画结束时,停留在最后一帧*********setFillAfter(true);setFillBefore(false); /*****动画结束时,停留在第一帧*********setFillAfter(false);setFillBefore(true); *
下面我们就来看一下弹幕实现的效果。
弹幕会出现重叠,这个问题还未解决
让我们开始看代码结构吧。
我们字体颜色的xml都写在了colors.xml中了,BarrageItem里面存放着我们的一些变量,而核心代码都在View中
BraagetItem.java
package com.example.bibibibibibibibi;import android.widget.TextView;import android.widget.TextView;/*** Created by lixueyong on 16/2/19.*/
public class BarrageItem {public TextView textView;//文本框public int textColor;//文本颜色public String text;//文本对象public int textSize;//文本的大小public int moveSpeed;//移动速度public int verticalPos;//垂直方向显示的位置public int textMeasuredWidth;//字体显示占据的宽度
}
在BarrageItem里面处理了弹幕的速度,大小,颜色,动画,等事件 在这个文件中 我注释的内容是我对弹幕重叠的操作代码,但是除了问题,有兴趣的可以看一下
package com.example.bibibibibibibibi;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import com.example.bibibibibibibibi.R.integer;
/*** Created by nzx on 16/5/30.*/
public class BarrageView extends RelativeLayout {private Context mContext;private BarrageHandler mHandler = new BarrageHandler();private Random random = new Random(System.currentTimeMillis());//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 = {"大头死变态", "老圩人最屌了", "唉这把中单是火男,难玩了", "大头是傻子", "世界上最长的路是套路", "英雄联盟最强的是补丁","我不会轻易的go die", "嘿嘿", "加班加班"};private int textCount;//文本的组数//private RelativeLayout Rparams;
// private List<BarrageItem> itemList = new ArrayList<BarrageItem>();
//实现RelativeLayout的重写的构造方法。/** //content 上下文 //AttributeSet 属性集//defStyleAttr 预设样式属性集//defStyleRes 预设样式资源属性集* * */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();}private void init() {textCount = itemText.length;int duration = (int) ((BARRAGE_GAP_MAX_DURATION - BARRAGE_GAP_MIN_DURATION) * Math.random());mHandler.sendEmptyMessageDelayed(0, duration);}@Override//Activity生命周期中,onStart, onResume, onCreate都不是真正visible的时间点,真正的visible时间点是onWindowFocusChanged()函数被执行时。//当你屏幕的焦点发生变化时候,想要操作什么也完全可以在这个方法里面执行。public void onWindowFocusChanged(boolean hasWindowFocus) {super.onWindowFocusChanged(hasWindowFocus);totalHeight = getMeasuredHeight();/*getHeight跟getMeasureHeight的区别* 实际上在当屏幕可以包裹内容的时候,他们的值相等,只有当view超出屏幕后,才能看出他们的区别:* getMeasuredHeight()是实际View的大小,与屏幕无关,而getHeight的大小此时则是屏幕的大小。* 当超出屏幕后, getMeasuredHeight() 等于 getHeight()加上屏幕之外没有显示的大小 * * *///获取每一行弹幕的最大高度lineHeight = getLineHeight();//我们整个弹幕的高度view/每一行的最大弹幕高度=totalLine = totalHeight / lineHeight;}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;}//弹幕在y轴上出现的位置item.verticalPos = random.nextInt(totalLine) * lineHeight;
// itemList.add(item);showBarrageItem(item);}private void showBarrageItem(final BarrageItem item) {
//paddingLeft是设置布局里面的内容左边的距离,这样我们这就可以让这个弹幕的textview完全消失int leftMargin = this.getRight() - this.getLeft() - this.getPaddingLeft();
//这里我们通过动态的方式去设置一些我们布局的属性。
// int verticalMargin = getRandomTopMargin();
// item.textView.setTag(verticalMargin);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) {}@Override//当我们动画结束的时候,清除该条弹幕public void onAnimationEnd(Animation animation) {item.textView.clearAnimation();BarrageView.this.removeView(item.textView);}@Override//动画被取消的时候出发public void onAnimationRepeat(Animation animation) {}});item.textView.startAnimation(anim);}//private TranslateAnimation generateTranslateAnim(BarrageItem item, int leftMargin) {//这里我们有四个参数(动画开始的x点,结束点,开始y轴点,结束的y点)TranslateAnimation anim = new TranslateAnimation(leftMargin, -item.textMeasuredWidth, 0, 0);//我们设置动画的持续时间,弹幕移动多久,我们就持续多久动画anim.setDuration(item.moveSpeed);// Interpolator 被用来修饰动画效果,定义动画的变化率,可以使存在的动画效果accelerated(加速),decelerated(减速),repeated(重复),bounced(弹跳)等。/** AccelerateDecelerateInterpolator 在动画开始与结束的地方速率改变比较慢,在中间的时候加速AccelerateInterpolator 在动画开始的地方速率改变比较慢,然后开始加速AnticipateInterpolator 开始的时候向后然后向前甩AnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值BounceInterpolator 动画结束的时候弹起CycleInterpolator 动画循环播放特定的次数,速率改变沿着正弦曲线DecelerateInterpolator 在动画开始的地方快然后慢LinearInterpolator 以常量速率改变OvershootInterpolator 向前甩一定值后再回到原来位置* */anim.setInterpolator(new AccelerateDecelerateInterpolator());/** fillBefore是指动画结束时画面停留在此动画的第一帧;fillAfter是指动画结束是画面停留在此动画的最后一帧。Java代码设置如下:/*****动画结束时,停留在最后一帧*********setFillAfter(true);setFillBefore(false); /*****动画结束时,停留在第一帧*********setFillAfter(false);setFillBefore(true); * * */anim.setFillAfter(true);return anim;}/*** 计算TextView中字符串的长度** @param text 要计算的字符串* @param Size 字体大小* @return TextView中字符串的长度*///因为我们的弹幕包裹在一个矩形中public float getTextWidth(BarrageItem item, String text, float Size) {Rect bounds = new Rect();TextPaint paint;paint = item.textView.getPaint();//这里参数是获取文本对象,开始的长度,结束的长度,我们绘制好的矩形框paint.getTextBounds(text, 0, text.length(), bounds);return bounds.width();}/*** 获得每一行弹幕的最大高度** @return*/private int getLineHeight() {BarrageItem item = new BarrageItem();String tx = itemText[0];item.textView = new TextView(mContext);item.textView.setText(tx);item.textView.setTextSize(maxSize);Rect bounds = new Rect();TextPaint paint;paint = item.textView.getPaint();paint.getTextBounds(tx, 0, tx.length(), bounds);return bounds.height();}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());//多个消息可以使用同一个handler, 通过what不同区分不同的消息来源, 从而获取消息内容this.sendEmptyMessageDelayed(0, duration);}}//记录一下当前在显示弹幕的高度,避免弹幕出现重叠private Set<integer> existMarginValues = new HashSet<>();private int linesCount;
// private int getRandomTopMargin()
// {
// //计算弹幕的空间高度
// if(totalLine==0)
// {
// totalLine=Rparams.getBottom()-Rparams.getTop()-Rparams.getPaddingTop()
// -Rparams.getPaddingBottom();
// if (totalHeight==0) {
// totalHeight = getMeasuredHeight();
// lineHeight = getLineHeight();
// totalLine = totalHeight / lineHeight;
// }
// //检查重叠
// while (true) {
// int randomIndex = (int) (Math.random() * linesCount);
// int marginValue = (int) (randomIndex * (totalLine / linesCount));
//
// if (!existMarginValues.contains(marginValue)) {
// existMarginValues.add(marginValue);
// return marginValue;
// }
// }
//
// // }}
BarrageActivity.java
在这个类里面我们可以去进行一些事件,但是我这里没有去处理,大家按自己的需求来。
package com.example.bibibibibibibibi;import android.app.Activity;
import android.os.Bundle;/*** Created by lixueyong on 16/2/19.*/
public class BarrageActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_barrage);}}
还有一些关于颜色的xml 大家可以通过demo去看下了,这样我们就实现了类似于bibibi弹幕的功能,是不是很简单(ps:哪里简单了(手动蔑视))。
等我把弹幕重叠的bug解决,我在博客上也会更新的。
demo下载地址:http://download.csdn.net/detail/ningzhouxu/9535392
今后我会更新更多有趣好玩的博客的。
教你一步步实现bibibi弹幕功能。相关推荐
- Android弹幕功能实现,模仿斗鱼直播的弹幕效果
转载请注明出处:http://blog.csdn.net/sinyu890807/article/details/51933728 本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭 ...
- 教你一步步搞定 Handoff
Yosemite 已经正式上线,相信很多筒子已经试过了其中最让人兴奋的 Continuity 功能."Continuity"功能包含了能跨平台兼容的AirDrop.可在iPad和M ...
- 年会弹幕文字_活动现场互动弹幕_教你大屏幕上的弹幕怎么做
学校举办民谣比赛.主持人大赛.元旦晚会.迎新晚会.毕业晚会之类的校园活动时候,参与的学生人数那叫一个多,这也给活动主办方带来了不小的困扰:年年都是那些花样儿,不来点新鲜点子很难吸引到学生们.活动现场要 ...
- 填充图片颜色计算机,教你一步步(电脑软件)绘制款式图+上色填充面料
原标题:教你一步步(电脑软件)绘制款式图+上色填充面料 软件ps(Adobe PhotoShop) 电脑+鼠标+键盘 使用钢笔工具绘制款式图 1.扫描:将人体草稿写进电脑,保存. 2.然后用Illus ...
- 隐藏esp_仅需一分钟教你看懂汽车内的隐藏功能,哪些功能是你不知道的?
车内的按键多种多样,而且越高档的车,按键就越多.除了少数国产车,绝大部分车辆的按键标识都是用英文字母表示,从而导致不少车主只能通过查看说明书才知道是什么意思. 今天小编整理了车内各种按键标识,不是很清 ...
- JavaScript css3模拟简单的视频弹幕功能
最近相对比较空闲,想写一些东西写着玩.就尝试写了一个demo模拟了最简单的视频弹幕功能~~. 思路: 设置一个<div>和所播放的video的大小一致,把这个div标签蒙在video上面用 ...
- 因弹幕系统技术升级 B站即日起至6月6日关闭弹幕功能
昨日晚间,B站官方微博发布声明称,因弹幕系统技术升级,从即日起至6月6日网站将暂时关闭弹幕功能. 在日前的第七届网络视听大会上,B站董事长兼CEO陈睿透露,2019年至今,已有2027万人在这家名为哔 ...
- html段落自动删除,利用JS代码自动删除稿件的普通弹幕功能
事情的起因是在b站投稿了一个高级弹幕测试的视频(av9940487),但是由于b站的弹幕池机制是新的弹幕顶掉旧的弹幕,所以导致一些人发的高级弹幕很快就被顶掉了. 所以就想着写个脚本来自动删除属性为普通 ...
- 用python turtle画龙猫_【跟着弹簧学画画】教你一步步画出一只超萌的龙猫来!...
原标题:[跟着弹簧学画画]教你一步步画出一只超萌的龙猫来! 龙猫,日文音译过来是豆豆龙,今天咱们就来画一个吧! 照旧先来感受下动态图↓ 1.先画耳朵,然后画出头部和身体,因为龙猫是圆滚滚的一只 画出胳 ...
- php怎么实现弹幕,HTML如何利用canvas实现弹幕功能
本篇文章主要介绍HTML如何利用canvas实现弹幕功能,感兴趣的朋友参考下,希望对大家有所帮助. 简介 最近在做大作业的时候需要做一个弹幕播放器.借鉴了一下别人的源码自己重新实现了一个,演示如下 主 ...
最新文章
- android 首页6个碎片,Android 单帧碎片
- Spring Security OAuth2源码解析(一)
- 利用SOS扩展库进入高阶.NET6程序的调试
- JavaScript时间事件:setTimeout和setInterval
- M1兼容性怎么样?关于M1版MacBook兼容软件的测试方法
- mysql currentuser_MySQL中DATABASE()和CURRENT_USER()函数的示例详解
- vmware虚拟化服务器cpu超线程,VMware vSphere的配置方法最佳方案从而提高性能
- 天池学习赛:工业蒸汽量预测2——特征工程
- 【iOS QR Code】集成ZXingWidget(XCode Version 4.5.2,iOS 6.0 SDK)
- 《Android游戏开发详解》——第2章,第2.13节调用对象的行为
- Linux中inode值是什么?
- android多个网络请求如何依次执行,Android 并发和串行网络请求
- Python分析王者峡谷中英雄信息
- origin 2018安装教程与安装包
- 深扒Mobileye—与特斯拉分手,被英特尔收购,现在又成了蔚来的救星?
- Inverting Convolutional Networks with Convolutional Networks 论文理解
- linux命令scp(复制文件和目录)详解及cp和scp命令的使用方法
- 日本战国武将绰号与称号一览表
- Python-Selenium-OSError: [WinError 6] 句柄无效
- ISO26262功能安全 安全等级和量化指标
热门文章
- MacOS Big Sur 11.2.1 (20D75) 纯净恢复版黑苹果镜像下载
- MacOS Ventura 13.0.1 (22A400) 正式版带 OC 0.8.6 and winPE 双分区原版黑苹果镜像
- MacOS Big Sur 11.5.2 (20G95) OC 0.7.2 / Cl 5138 / PE 三分区原版黑苹果镜像
- 量子计算机慕课,计算机组成原理-中国大学mooc-题库零氪
- inter Fortran安装匹配VS2012
- 美媒:马斯克已掌管推特 立即开除CEO、CFO,新CEO据传是曾经卖牛肉的中国人
- pe_xscan做了几个改动
- HTML5期末大作业:小说网页设计——在线阅读7页(代码质量好) 学生DW网页设计作业源码 web课程设计网页规划与设计
- php flea,FleaPHP - 开发框架 - PHP开源网(PHP-OPEN.ORG)
- css滑动门技术的应用,CSS滑动门技术