我只是搬运:https://blog.csdn.net/HighForehead/article/details/55520199

写的很好很详细,挺有参考价值的

demo直通车:https://download.csdn.net/download/highforehead/9757126

直播和看视频中越来越火的控件---弹幕(Danmaku)

本文即介绍怎样实现简单的弹幕效果:咱们使用的是哔哩哔哩开源的弹幕效果库 DanmakuFlameMaster( github地址:https://github.com/Bilibili/DanmakuFlameMaster).

必需:首先咱们在项目主工程app/build.gradle中的dependencies闭包中添加如下依赖:

compile 'com.github.ctiao:DanmakuFlameMaster:0.5.3'

这样我们就将DanmakuFlameMaster库引入到当前项目中了.
开始展示Demo的代码给大家:

首先看咱们的布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000">

<VideoView
android:id="@+id/video_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>

<master.flame.danmaku.ui.widget.DanmakuView
android:id="@+id/danmaku_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<LinearLayout
android:id="@+id/operation_layout"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:background="#fff"
android:visibility="gone">

<EditText
android:id="@+id/edit_text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
/>

<Button
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="发送" />
</LinearLayout>

</RelativeLayout>
.
背景色为黑色,承载我是用的Video来播放本地或者网络视频,DanmakuView即是咱们的弹幕控件,LinearLayout内包含输入框和发送按钮.当然这些都是最普通的控件,最终的界面当然是由您来设定.

接下来看咱们的MainActivity的代码,如下:
.
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.VideoView;

import java.util.Random;

import master.flame.danmaku.controller.DrawHandler;
import master.flame.danmaku.danmaku.model.BaseDanmaku;
import master.flame.danmaku.danmaku.model.DanmakuTimer;
import master.flame.danmaku.danmaku.model.IDanmakus;
import master.flame.danmaku.danmaku.model.android.DanmakuContext;
import master.flame.danmaku.danmaku.model.android.Danmakus;
import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
import master.flame.danmaku.ui.widget.DanmakuView;

public class MainActivity extends AppCompatActivity {
private boolean showDanmaku;
//弹幕控件
private DanmakuView danmakuView;
//DanmakuContext 字体实例
private DanmakuContext danmakuContext;
private BaseDanmakuParser parser = new BaseDanmakuParser() {
@Override
protected IDanmakus parse() {
return new Danmakus();
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化VideoView控件
final VideoView videoView = (VideoView) findViewById(R.id.video_view);
//指定好VideoView的本地路径地址 SD卡根目录的xxx.mp4文件
videoView.setVideoPath(Environment.getExternalStorageDirectory() + "/xxx.mp4");
//访问网络视频
//Uri uri = Uri.parse("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4");
//设置视频控制器
//videoView.setMediaController(new MediaController(this));
//设置视频路径
// videoView.setVideoURI(uri);
//开始播放
videoView.start();

new android.os.Handler().postDelayed(new Runnable() {
@Override
public void run() {
videoView.pause();
}
}, 0);

//初始化弹幕控件
danmakuView = (DanmakuView) findViewById(R.id.danmaku_view);
//默认为true 在模拟器上运行有问题
danmakuView.enableDanmakuDrawingCache(true);
//看源码得知是一个接口 怎么实现还是要咱们去重写其中的方法
danmakuView.setCallback(new DrawHandler.Callback() {
@Override
public void prepared() {
//把变量置为 true
showDanmaku = true;
//开始运行弹幕控件
danmakuView.start();
//随机生成一些弹幕内容以供测试
generateSomeDanmaku();
}

@Override
public void updateTimer(DanmakuTimer timer) {

}

@Override
public void danmakuShown(BaseDanmaku danmaku) {

}

@Override
public void drawingFinished() {

}
});
//调用 DanmakuContext.create() 完成DanmakuContext的实例化.
danmakuContext = DanmakuContext.create();
danmakuView.prepare(parser, danmakuContext);
//初始化含有输入框和按钮的线性布局
final LinearLayout operationLayout = (LinearLayout) findViewById(R.id.operation_layout);
//初始化发送按钮
final Button send = (Button) findViewById(R.id.send);
//输入框输入内容
final EditText editText = (EditText) findViewById(R.id.edit_text);
//适时的让输入框显现或隐藏
danmakuView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (operationLayout.getVisibility() == View.GONE) {
operationLayout.setVisibility(View.VISIBLE);
} else {
operationLayout.setVisibility(View.GONE);
}
}
});
//发送按钮的点击事件
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String content = editText.getText().toString();
if (!TextUtils.isEmpty(content)) {
//因为是自己的内容,所以传一个true过去,方法内部会判断这个变量
addDanmaku(content, true);
//再把输入框置为空
editText.setText("");
}
}
});
//获取到窗体的顶级父类并设置状态栏的显示隐藏
getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
@Override
public void onSystemUiVisibilityChange(int visibility) {
if (visibility == View.SYSTEM_UI_FLAG_VISIBLE) { //显示状态栏,Activity不全屏显示
onWindowFocusChanged(true);
}
}
});
}

/**
* 向弹幕View中添加一条弹幕
*
* @param content 弹幕的具体内容
* @param withBorder 弹幕是否有边框
*/
private void addDanmaku(String content, boolean withBorder) {
//BaseDanmaku 您可以点击进入查看源码实现
// 弹幕的相关设置:弹幕优先级 颜色 时长 文本 Z轴 Y轴 阴影 描边
// 下划线 内边距 宽度 高度 存活时间 是否是直播弹幕
BaseDanmaku danmaku = danmakuContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
danmaku.text = content; //文本
danmaku.padding = 5; //内边距
danmaku.textSize = sp2px(20); //字体大小
danmaku.textColor = Color.WHITE; //文本颜色
danmaku.setTime(danmakuView.getCurrentTime()); //显示时长 偏移时间
//如果是true 证明是自己的弹幕,那么就可以更改自己想要的颜色了
if (withBorder) {
danmaku.borderColor = Color.GREEN;
}
//调用底层代码 把弹幕内容添加到LinkedList<Long> mDrawTimes;
danmakuView.addDanmaku(danmaku);
}

/**
* 随机生成一些弹幕内容以供测试
*/
private void generateSomeDanmaku() {
new Thread(new Runnable() {
@Override
public void run() {
while (showDanmaku) {
int time = new Random().nextInt(300);
String content = "" + time + time;
addDanmaku(content, false);
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}

/**
* sp转px的方法。
*/
public int sp2px(float spValue) {
final float fontScale = getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}

@Override//表示Activity正在停止.
protected void onPause() {
super.onPause();
//如果弹幕控件不为空 && 弹幕控件的线程还存活
if (danmakuView != null && danmakuView.isPrepared()) {
//暂停运行弹幕控件
danmakuView.pause();
}
}

@Override//表示Activity前台并可与用户交互.
protected void onResume() {
super.onResume();
if (danmakuView != null && danmakuView.isPrepared() && danmakuView.isPaused()) {
danmakuView.resume();
}
}

@Override//表示Activity即将被销毁.
protected void onDestroy() {
super.onDestroy();
//把变量置为false
showDanmaku = false;
//如果弹幕控件还存在.调用release(); 底层调用stop(),并把底层的LinkedList<Long> mDrawTimes 置为空;
if (danmakuView != null) {
danmakuView.release();
danmakuView = null;
}
}

@Override//都说这个函数才会使用户可以与应用真正开始进行交互.
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
//看了底层后得知 Build.VERSION.SDK_INT == 20 ;
if (hasFocus && Build.VERSION.SDK_INT >= 19) {
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(
//这个标志来帮助你的应用维持一个稳定的布局.
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
//Activity全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity顶端布局部分会被状态遮住。
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
//ctivity全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity顶端布局部分会被状态遮住.
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
//ctivity全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity顶端布局部分会被状态遮住.
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
//Activity全屏显示,且状态栏被隐藏覆盖掉.
| View.SYSTEM_UI_FLAG_FULLSCREEN
//安卓4.4 新增.
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
}
}

如上,在安卓设备上,一个简单的弹幕Demo就可以实现了.

Android Studio 直播弹幕的更多相关文章

  1. Mac下载安装Android Studio教程

    今天把公司闲置的一台Mac-mini重装了下系统感觉用着速度还不错,平时上班用的机器USB有些问题,所以打算用这台Mac.以往开发用Intellij Idea就够用,但是这次项目引用的jar包太多,遭 ...

  2. Android 如何直播RTMP流

    在android上,视频/音频流直播是极少有人关注的一部分.每当我们讨论流媒体,RTMP(Real Time Messaging Protocol)是不可或缺的.RTMP是一个基本的视频/音频直播流协 ...

  3. ubuntu12.04 android studio 安装

    ubuntu12.04 android studio 安装 分类: android 2014-02-17 15:57 10756人阅读 评论(0) 收藏 举报 1.下载JDK ,我下载的是jdk-7u ...

  4. Android 视频直播 SDK

    Android 视频直播 SDK接入说明 一.名词解释 分辨率:用于计算机视频处理的图像,以水平和垂直方向上所能显示的像素数来表示分辨率.常见视频分辨率的有1080P即1920x1080,720P即1 ...

  5. 内存测试——Android Studio中对应进程的Heap

    通过Android Studio的Heap查看该程序的目前占用内存大小,多次进出界面,观察内存内存大小的变化.用Heap监测应用进程使用内存情况的步骤如下: 1. 启动Android Studio—& ...

  6. Android studio 插件之 GsonFormat (自己主动生成javabean)

    概述 相信大家在做开发的过程中都写过非常多的javabean ,非常多情况下 都是一个列表数据就是一个单独的javabean.假设大家自己敲的话费时费力 还非常easy敲错. 今天给大家推荐一个插件 ...

  7. (转载) android studio library生成jar包和aar的方法总结

    android studio library生成jar包和aar的方法总结 标签: android学习文档jar和aar的使用与生成gradle 2016-11-25 10:39 1782人阅读 评论 ...

  8. (转载) Android Studio你不知道的调试技巧

    Android Studio你不知道的调试技巧 标签: android studio 2015-12-29 16:05 2514人阅读 评论(0) 收藏 举报  分类: android(74)    ...

  9. (转载)Mac下使用Android Studio 获取 SHA1和MD5

    Mac下使用Android Studio 获取 SHA1和MD5 2015-08-10 15:38 1776人阅读 评论(1) 收藏 举报  分类: Android(14)  版权声明:本文为博主原创 ...

随机推荐

  1. 面向对象原生JavaScript案例炫彩小球

    面向对象其实对于初学者来说还是比较难以理解的,以前看到一个面试题目 面向对象是什么? 面向对象是一种思想,千万别入坑了: 这次给大家带来的是一个鼠标移动产生小球的案例,不是我不想给大家分享如何去认识面 ...

  2. sed 修改文本

    修改文本是指将所匹配的文本行利用新文本替代,sed编辑命令的修改文本符号为 c\, [ sed]$ more input [ sed]$ more aa.sed #!/bin/sed -f //c\ ...

  3. SQL解析

    private static String getCountSql(String sql) { return "select count(*) from "+cutOrderByO ...

  4. 高可用Redis(五):瑞士军刀之慢查询,Pipeline和发布订阅

    1.慢查询 1.1 慢查询的生命周期 步骤一:client通过网络向Redis发送一条命令 步骤二:由于Redis是单线程应用,可以把Redis想像成一个队列,client执行的所有命令都在排队等着s ...

  5. SQL语句完整的执行顺序(01)

    一.sql语句的执行步骤:  1)语法分析,分析语句的语法是否符合规范,衡量语句中各表达式的意义.  2) 语义分析,检查语句中涉及的所有数据库对象是否存在,且用户有相应的权限.  3)视图转换,将涉 ...

  6. wx:for获取 data-xxx 自定义的属性

    今天在写wx:for循环时,在事件对象上e.target.dataset上一直拿不到自定义属性 data-id. 示例: <view wx:for='{{list}}' wx:key='{{it ...

  7. html网页引用中文字体,解决加载缓慢办法

    [ttf 压缩]html网页引用中文字体,文件过大,加载缓慢的解决办法[字蛛][web font] [字蛛]http://font-spider.org/ 先安装好 NodeJS,然后执行: npm ...

  8. 获取Shell脚本当前的目录

    https://qiushao.net/article/1489983836453?p=1&m=0 SCRIPT_DIR=$(cd $(dirname ${BASH_SOURCE[0]}); ...

  9. 烽火2640路由器命令行手册-12-IBM网络配置命令

    IBM网络配置命令 目  录 第1章 DLSW配置命令... 1 1.1 DLSW配置命令... 1 1.1.1 dlsw local-peer 1 1.1.2 dlsw remote-peer 3 ...

  10. vs2017 EFCore 迁移数据库命令

    项目结构: 首先引用 Microsoft.EntityFrameworkCore.Tools Microsoft.EntityFrameworkCore.Design 增加类DesignTimeDbC ...