二、原理解析

=================================================================

1.开始的思路。


(1)自定义ViewGroup-XCDanmuView,继承RelativeLayout来实现,当然也可以继承其他三大布局类。先展示一下项目布局。

(2)需要将界面设置为横屏,并对它进行一些配置。下面是清单文件的代码。

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android=“http://schemas.android.com/apk/res/android”

package=“com.mythmayor.a1805danmudemo”>

<application

android:allowBackup=“true”

android:icon="@mipmap/ic_launcher"

android:label="@string/app_name"

android:supportsRtl=“true”

android:theme="@style/AppTheme">

<activity

android:name=".MainActivity"

android:configChanges=“orientation|keyboardHidden|screenLayout|screenSize”

android:screenOrientation=“landscape”>

(3)我在这里用到了哔哩哔哩开源的弹幕效果库DanmakuFlameMaster(这个库的功能也比较强大,但本篇文章中可能只用到其基本功能,有兴趣的同学可以到其GitHub上进行学习)。需要配置到build.gradle的dependencies中。

dependencies {

compile fileTree(dir: ‘libs’, include: [’*.jar’])

androidTestCompile(‘com.android.support.test.espresso:espresso-core:2.2.2’, {

exclude group: ‘com.android.support’, module: ‘support-annotations’

})

compile ‘com.android.support:appcompat-v7:26.0.0-alpha1’

testCompile ‘junit:junit:4.12’

compile ‘com.github.ctiao:DanmakuFlameMaster:0.9.25’

}

2.把控效果


在观看直播或视频的时候,我们经常能看到弹幕的效果。首先我们从布局上讲一下,其实非常简单,布局最下层是播放器视图,中间那层一般则是弹幕视图层,最上层是操作界面的视图层。这样一说大家的心里是不是就有一个很清晰的结构了。那么下面就直接上布局的代码了。

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:tools=“http://schemas.android.com/tools”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:background="#000000"

tools:context=“com.mythmayor.a1805danmudemo.MainActivity”>

<VideoView

android:id="@+id/video_view"

android:layout_width=“match_parent”

android:layout_height=“match_parent”

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=“Send” />

3.核心代码。在这里有几点是需要说明的。


(1)首先播放视频的话这里用到的是VideoView,使用起来也非常简单,先要设置一个视频文件的路径:String uri = “android.resource://” + getPackageName() + “/” + R.raw.danmu;然后调用start方法即可播放视频了。

(2)关于弹幕库的使用,可参考下面代码进行理解。我们需要创建一个DanmakuContext的实例和一个弹幕的解析器(这里直接创建了一个全局的BaseDanmakuParser),创建完成后就可以调用DanmakuView的prepare()方法了,调用这一方法后会自动调用回调函数中的prepared()方法,这个方法中调用了start方法,弹幕就此开始工作了。

package com.mythmayor.a1805danmudemo;

import android.app.Activity;

import android.graphics.Color;

import android.os.Build;

import android.os.Bundle;

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 Activity {

private boolean showDanmaku;

private DanmakuView danmakuView;

private DanmakuContext danmakuContext;

private BaseDanmakuParser parser = new BaseDanmakuParser() {

@Override

protected IDanmakus parse() {

return new Danmakus();

}

};

@O

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》浏览器打开:qq.cn.hn/FTe 免费领取

verride

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

VideoView videoview = (VideoView) findViewById(R.id.video_view);

String uri = “android.resource://” + getPackageName() + “/” + R.raw.danmu;

videoview.setVideoPath(uri);

//videoview.setVideoURI(Uri.parse(uri));

videoview.start();

danmakuView = (DanmakuView) findViewById(R.id.danmaku_view);

danmakuView.enableDanmakuDrawingCache(true);

danmakuView.setCallback(new DrawHandler.Callback() {

@Override

public void prepared() {

showDanmaku = true;

danmakuView.start();

generateSomeDanmaku();

}

@Override

public void updateTimer(DanmakuTimer timer) {

}

@Override

public void danmakuShown(BaseDanmaku danmaku) {

}

@Override

public void drawingFinished() {

}

});

danmakuContext = DanmakuContext.create();

danmakuView.prepare(parser, danmakuContext);

final LinearLayout operationLayout = (LinearLayout) findViewById(R.id.operation_layout);

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 v) {

if (operationLayout.getVisibility() == View.GONE) {

operationLayout.setVisibility(View.VISIBLE);

} else {

operationLayout.setVisibility(View.GONE);

}

}

});

send.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

String content = editText.getText().toString();

if (!TextUtils.isEmpty(content)) {

addDanmaku(content, true, Color.GREEN);

editText.setText("");

}

}

});

getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {

@Override

public void onSystemUiVisibilityChange(int visibility) {

if (visibility == View.SYSTEM_UI_FLAG_VISIBLE) {

onWindowFocusChanged(true);

}

}

});

}

/**

  • 向弹幕View中添加一条弹幕

  • @param content 弹幕的具体内容

  • @param withBorder 弹幕是否有边框

*/

private void addDanmaku(String content, boolean withBorder) {

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());

if (withBorder) {

danmaku.borderColor = Color.GREEN;

}

danmakuView.addDanmaku(danmaku);

}

/**

  • 弹幕View中添加一条弹幕

  • @param content 弹幕的具体内容

  • @param withBorder 弹幕是否有边框

  • @param textColor 弹幕字体颜色

*/

private void addDanmaku(String content, boolean withBorder, int textColor) {

BaseDanmaku danmaku = danmakuContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);

danmaku.text = content;

danmaku.padding = 5;

danmaku.textSize = sp2px(20);

danmaku.textColor = textColor;

danmaku.setTime(danmakuView.getCurrentTime());

if (withBorder) {

danmaku.borderColor = Color.GREEN;

}

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 (Exception e) {

e.printStackTrace();

}

}

}

}).start();

}

/**

  • sp转px的方法。

*/

public int sp2px(float spValue) {

final float fontScale = getResources().getDisplayMetrics().scaledDensity;

return (int) (spValue * fontScale + 0.5f);

}

@Override

protected void onPause() {

super.onPause();

if (danmakuView != null && danmakuView.isPrepared()) {

danmakuView.pause();

}

}

@Override

protected void onResume() {

super.onResume();

if (danmakuView != null && danmakuView.isPrepared() && danmakuView.isPaused()) {

danmakuView.resume();

}

}

@Override

protected void onDestroy() {

super.onDestroy();

showDanmaku = false;

if (danmakuView != null) {

danmakuView.release();

danmakuView = null;

}

}

/**

  • 沉浸式状态栏效果

*/

@Override

public void onWindowFocusChanged(boolean hasFocus) {

super.onWindowFocusChanged(hasFocus);

if (hasFocus && Build.VERSION.SDK_INT >= 19) {

View decorView = getWindow().getDecorView();

decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE

| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION

| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION

| View.SYSTEM_UI_FLAG_FULLSCREEN

| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);

}

}

}

4、显示的一些增强功能


使用一个相对布局,弹幕浮于视频之上,底部是弹幕文字输入栏,右下角为弹幕发送按钮视频弹幕的。

1.关于弹幕库的使用,需要创建一个DanmakuContext的实例和一个弹幕的解析器(这里直接创建了一个全局的BaseDanmakuParser),创建完成后就可以调用DanmakuView的prepare()方法了,调用这一方法后会自动调用回调函数中的prepared()方法,在这个方法中调用了start方法,弹幕就此开始工作了;

2.需要在onPause()、onResume()、onDestroy()方法中执行一些操作,以保证DanmakuView的资源可以得到释放。

代码:

package com.mythmayor.a1805danmudemo;

import android.content.Context;

import android.graphics.Color;

import android.os.Build;

import android.os.Bundle;

import android.support.v7.app.AppCompatActivity;

import android.text.TextUtils;

import android.util.Log;

import android.view.View;

import android.view.inputmethod.InputMethodManager;

android-实现一个简单的视频弹幕,Android未来路在何方相关推荐

  1. android-实现一个简单的视频弹幕,Android已死

    android:id="@+id/edit_text" android:layout_width="0dp" android:layout_height=&qu ...

  2. Android之使用VideoView组件播放一个简单的视频

    1.在Android开发中,提供了VideoView组件用来播放视频文件.首先,要使用这个组件来播放视频,必须在布局文件下添加VideoView组件,然后再到Activity里获取这个组件,然后调用这 ...

  3. android实现计算器功能吗,利用Android实现一个简单的计算器功能

    利用Android实现一个简单的计算器功能 发布时间:2020-11-20 16:25:01 来源:亿速云 阅读:90 作者:Leah 今天就跟大家聊聊有关利用Android实现一个简单的计算器功能, ...

  4. 初识Android 制作一个简单的记账本

    初识Android 制作一个简单的记账本 主要功能 实现一个记账本页面 可以添加数据并更新到页面中 主要步骤 运行截图 主页面 点击红色按钮弹出添加页面 完成后自动更新到目录下 主要功能 实现一个记账 ...

  5. Android 实现一个简单的文件下载工具

    下载应该是每个App都必须的一项功能,不采用第三方框架的话,就需要我们自己去实现下载工具了.如果我们自己实现可以怎么做呢? 首先如果服务器文件支持断点续传,则我们需要实现的主要功能点如下: 多线程.断 ...

  6. JavaScript css3模拟简单的视频弹幕功能

    最近相对比较空闲,想写一些东西写着玩.就尝试写了一个demo模拟了最简单的视频弹幕功能~~. 思路: 设置一个<div>和所播放的video的大小一致,把这个div标签蒙在video上面用 ...

  7. Android之使用MediaPlayer和SurfaceView组件播放一个简单的视频

    1.MediaPlayer除了可以播放音乐外,还可以播放视频,但是使用MediaPlayer播放音乐时,没有提供图像输出界面,可以使用SurfaceView组件来显示视频画面,首先,必须在布局文件ac ...

  8. Android Compose——一个简单的Bilibili APP

    Bilibili移动端APP 简介 依赖 效果 登录 效果 WebView 自定义TobRow的Indicator大小 首页 推荐 LazyGridView使用Paging3 热门 排行榜 搜索 模糊 ...

  9. 用java开发一个简单的安卓程序,Android NDK开发简单程序分享(Hello Word!)

    在之前的博客中已经为大家介绍了,如何在win环境下配置DNK程序,本篇我将带大家实现一个简单的Hello jni程序,让大家真正感受一下NDK开发的魅力.这里我们选择使用C+JAVA开发Android ...

  10. Android 中一个简单垂直跑马灯的实现

    记录一个Android中简单实现垂直跑马灯功能的方法:实现了垂直跑马灯的功能.记录一下以便日后查看: 首先在MainActivity下新建一个名为ScrollTextView的.java 文件 Scr ...

最新文章

  1. Matlab中plot基本用法
  2. JavaScript面向对象编程之Singleton类
  3. iCloud1_Getting Started
  4. extundelete应用实战
  5. 计算机软件乘除,基于单片机的智能计算机程序 可以实现加减乘除运算
  6. Thinkpad SL400安装黑苹果10.8.4全纪录
  7. Python程序员都会喜欢的6个库
  8. ubuntu虚拟环境
  9. iOS xcode The certificate used to sign Administrator has either expired or has been revoked. An u
  10. 如何快速掌握一门新的技术?
  11. Spring Cloud Alibaba学习记录
  12. 机器学习之recall、precision、accuracy
  13. jquery 处理页面的事件详解
  14. ssm+Vue计算机毕业设计学科竞赛赛场安排系统(程序+LW文档)
  15. Keras 在windows环境下安装配置教程
  16. 三亚免税店积分抵现_海南放大招!10万购物免税额、离岛半年可补购,一文教你买转海南自贸港...
  17. 洛谷:P2832 行路难(堆优化Dijkstra(错解)bfs(正解) + 记录路径)
  18. C语言学习笔记 | 进阶 | 文件操作详解(万字精心制作)
  19. 霍尔传感器工作原理简介
  20. 阿里云ACP云计算认证

热门文章

  1. 金蝶记账王和易记账哪个好_代理记账比招聘全职会计好在哪-义乌丹诚代理记账...
  2. 适合C语言学习的书籍推荐 | 初学者必备
  3. 地方舆情监测软件排名怎么评估的参考方法详解
  4. 《Go Web编程实战派——从入门到精通》学习笔记之第1章 Go基础入门
  5. 华为hcip认证考试题库有哪些内容?华为hcip认证考试题库试题举例
  6. 计算机乐谱吃鸡,Capo可自动识别音乐生成乐谱
  7. 比特鹏哥c语言视频,跟着鹏哥学习C语言
  8. c语言程序 题库管理,C语言程序设计题库管理系统-20210412073918.docx-原创力文档
  9. oracle excel vba6,vba6.dll下载
  10. OLT操作命令集及排障