Android 实现仿网络直播弹幕功能详解及实例_Android

Android 网络直播弹幕

               最近看好多网络电视,播放器及直播都有弹幕功能,自己周末捣鼓下并实现,以下是网上的资料,大家可以看下。

现在网络直播越来越火,网络主播也逐渐成为一种新兴职业,对于网络直播,弹幕功能是必须要有的,如下图:

首先来分析一下,这个弹幕功能是怎么实现的,首先在最下面肯定是一个游戏界面View,然后游戏界面上有弹幕View,弹幕的View必须要做成完全透明的,这样即使覆盖在游戏界面的上方也不会影响到游戏的正常观看,只有当有人发弹幕消息时,再将消息绘制到弹幕的View上面就可以了,下方肯定还有有操作界面View,可以让用户来发弹幕和送礼物的功能,原理示意图如下所示:

参照原理图,下面一步一步来实现这个功能。

实现视频的播放

activity_main.xml

<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"/>
</RelativeLayout> 

MainActivity.java

package com.jackie.bombscreen; 

import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.VideoView; 

public class MainActivity extends AppCompatActivity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  VideoView videoView = (VideoView) findViewById(R.id.video_view);
  videoView.setVideoPath(Environment.getExternalStorageDirectory() + "/xiaoxingyun.mp4");
  videoView.start();
 } 

 @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);
  }
 }
} 

最后别忘了设置AndroidMainfest.xml

效果如下:

实现弹幕的效果

接下来我们开始实现弹幕效果。弹幕其实也就是一个自定义的View,它的上面可以显示类似于跑马灯的文字效果。观众们发表的评论都会在弹幕上显示出来,但又会很快地移出屏幕,既可以起到互动的作用,同时又不会影响视频的正常观看。

我们可以自己来编写这样的一个自定义View,当然也可以直接使用网上现成的开源项目。那么为了能够简单快速地实现弹幕效果,这里我就准备直接使用由哔哩哔哩开源的弹幕效果库DanmakuFlameMaster。

DanmakuFlameMaster库的项目主页地址是:http://xiazai.jb51.net/201611/yuanma/DanmakuFlameMaster-master(jb51.net).rar

添加build.gradle依赖

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

<?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" />
</RelativeLayout>

修改MainActivity.java

package com.jackie.bombscreen; 

import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
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 mIsShowDanmaku;
 private DanmakuView mDanmakuView;
 private DanmakuContext mDanmakuContext; 

 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 videoView = (VideoView) findViewById(R.id.video_view);
  videoView.setVideoPath(Environment.getExternalStorageDirectory() + "/xiaoxingyun.mp4");
  videoView.start(); 

  mDanmakuView = (DanmakuView) findViewById(R.id.danmaku_view);
  mDanmakuView.enableDanmakuDrawingCache(true);
  mDanmakuView.setCallback(new DrawHandler.Callback() {
   @Override
   public void prepared() {
    mIsShowDanmaku = true;
    mDanmakuView.start();
    generateSomeDanmaku();
   } 

   @Override
   public void updateTimer(DanmakuTimer timer) { 

   } 

   @Override
   public void danmakuShown(BaseDanmaku danmaku) { 

   } 

   @Override
   public void drawingFinished() { 

   }
  }); 

  mDanmakuContext = DanmakuContext.create();
  mDanmakuView.prepare(parser, mDanmakuContext);
 } 

 /**
  * 向弹幕View中添加一条弹幕
  * @param content  弹幕的具体内容
  * @param withBorder 弹幕是否有边框
  */
 private void addDanmaku(String content, boolean withBorder) {
  BaseDanmaku danmaku = mDanmakuContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
  danmaku.text = content;
  danmaku.padding = 5;
  danmaku.textSize = sp2px(20);
  danmaku.textColor = Color.WHITE;
  danmaku.setTime(mDanmakuView.getCurrentTime());
  if (withBorder) {
   danmaku.borderColor = Color.GREEN;
  }
  mDanmakuView.addDanmaku(danmaku);
 } 

 /**
  * 随机生成一些弹幕内容以供测试
  */
 private void generateSomeDanmaku() {
  new Thread(new Runnable() {
   @Override
   public void run() {
    while(mIsShowDanmaku) {
     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
 protected void onPause() {
  super.onPause();
  if (mDanmakuView != null && mDanmakuView.isPrepared()) {
   mDanmakuView.pause();
  }
 } 

 @Override
 protected void onResume() {
  super.onResume();
  if (mDanmakuView != null && mDanmakuView.isPrepared() && mDanmakuView.isPaused()) {
   mDanmakuView.resume();
  }
 } 

 @Override
 protected void onDestroy() {
  super.onDestroy();
  mIsShowDanmaku = false;
  if (mDanmakuView != null) {
   mDanmakuView.release();
   mDanmakuView = 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);
  }
 }
} 

效果图如下:

加入操作界面

<?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="Send" />
 </LinearLayout>
</RelativeLayout> 
package com.jackie.bombscreen; 

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 mIsShowDanmaku;
 private DanmakuView mDanmakuView;
 private DanmakuContext mDanmakuContext; 

 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 videoView = (VideoView) findViewById(R.id.video_view);
  videoView.setVideoPath(Environment.getExternalStorageDirectory() + "/xiaoxingyun.mp4");
  videoView.start(); 

  mDanmakuView = (DanmakuView) findViewById(R.id.danmaku_view);
  mDanmakuView.enableDanmakuDrawingCache(true);
  mDanmakuView.setCallback(new DrawHandler.Callback() {
   @Override
   public void prepared() {
    mIsShowDanmaku = true;
    mDanmakuView.start();
    generateSomeDanmaku();
   } 

   @Override
   public void updateTimer(DanmakuTimer timer) { 

   } 

   @Override
   public void danmakuShown(BaseDanmaku danmaku) { 

   } 

   @Override
   public void drawingFinished() { 

   }
  }); 

  mDanmakuContext = DanmakuContext.create();
  mDanmakuView.prepare(parser, mDanmakuContext); 

  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);
  mDanmakuView.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)) {
     addDanmaku(content, true);
     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 = mDanmakuContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
  danmaku.text = content;
  danmaku.padding = 5;
  danmaku.textSize = sp2px(20);
  danmaku.textColor = Color.WHITE;
  danmaku.setTime(mDanmakuView.getCurrentTime());
  if (withBorder) {
   danmaku.borderColor = Color.GREEN;
  }
  mDanmakuView.addDanmaku(danmaku);
 } 

 /**
  * 随机生成一些弹幕内容以供测试
  */
 private void generateSomeDanmaku() {
  new Thread(new Runnable() {
   @Override
   public void run() {
    while(mIsShowDanmaku) {
     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
 protected void onPause() {
  super.onPause();
  if (mDanmakuView != null && mDanmakuView.isPrepared()) {
   mDanmakuView.pause();
  }
 } 

 @Override
 protected void onResume() {
  super.onResume();
  if (mDanmakuView != null && mDanmakuView.isPrepared() && mDanmakuView.isPaused()) {
   mDanmakuView.resume();
  }
 } 

 @Override
 protected void onDestroy() {
  super.onDestroy();
  mIsShowDanmaku = false;
  if (mDanmakuView != null) {
   mDanmakuView.release();
   mDanmakuView = 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);
  }
 }
} 

效果图如下:

自己发的弹幕有绿色边框,很容易区分。

基本上实现了弹幕的功能,当然,里面的知识点还有很多,这只是最基本的功能。有时间的话,建议学学DanmakuFlameMaster,里面还有很多炫酷的功能。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索android
网络直播弹幕
弹幕实例、婴儿毛衣编织实例详解、abaqus工程实例详解、android创意实例详解、c 编程实例详解,以便于您获取更多的相关知识。

时间: 2024-10-31 18:05:38

Android 实现仿网络直播弹幕功能详解及实例_Android的相关文章

Android 实现获取手机里面的所有图片详解及实例

Android 实现获取手机里面的所有图片详解及实例 实现代码: public class MainActivity extends Activity { //查看图片按钮 private Button look; private Button add; //显示图片名称的list ListView show_list; ArrayList names = null; ArrayList descs= null; ArrayList fileNames = null; @Override pro

Android实现炫酷的网络直播弹幕功能_Android

现在网络直播越来越火,网络主播也逐渐成为一种新兴职业,对于网络直播,弹幕功能是必须要有的,如下图: 首先来分析一下,这个弹幕功能是怎么实现的,首先在最下面肯定是一个游戏界面View,然后游戏界面上有弹幕View,弹幕的View必须要做成完全透明的,这样即使覆盖在游戏界面的上方也不会影响到游戏的正常观看,只有当有人发弹幕消息时,再将消息绘制到弹幕的View上面就可以了,下方肯定还有有操作界面View,可以让用户来发弹幕和送礼物的功能,原理示意图如下所示: 参照原理图,下面一步一步来实现这个功能.

Android实现炫酷的网络直播弹幕功能

现在网络直播越来越火,网络主播也逐渐成为一种新兴职业,对于网络直播,弹幕功能是必须要有的,如下图: 首先来分析一下,这个弹幕功能是怎么实现的,首先在最下面肯定是一个游戏界面View,然后游戏界面上有弹幕View,弹幕的View必须要做成完全透明的,这样即使覆盖在游戏界面的上方也不会影响到游戏的正常观看,只有当有人发弹幕消息时,再将消息绘制到弹幕的View上面就可以了,下方肯定还有有操作界面View,可以让用户来发弹幕和送礼物的功能,原理示意图如下所示: 参照原理图,下面一步一步来实现这个功能.

Android 破解视频App去除广告功能详解及解决办法总结

Android 破解视频App去除广告功能 作为一个屌丝程序猿也有追剧的时候,但是当打开视频app的时候,那些超长的广告已经让我这个屌丝无法忍受了,作为一个程序猿看视频还要出现广告那就是打我脸,但是我有没有钱买会员,只能靠着毕生技能去耍耍去除广告了.下面就来介绍一下如何进行视频广告的去除. 一.视频广告播放原理 首先我们需要了解的一个基本知识点那就是广告其实也是一段视频,那么他肯定有请求地址和播放地址.那么我们的思路就来了,如果能够得到这些地址的话,我们就可以去除广告了,为什么呢?因为我们知道所

网络营销软件主流功能详解

每个网络营销软件的功能模块都不尽相同,但主流的功能模块都比较类似,对于企业来说,真正能发挥作用的功能模块,主要有几个模板,今天,如邻网络把这几个功能模块向大家详细介绍一下: 第一:黄页注册登陆模块,这是所有网络营销软件的基础模块,发布企业信息的第一步,就是进行B2B平台批量注册,企业在这个平台上注册自己企业的账号,建立自己的公司黄页.这个模块,包括了,账号注册,公司信息提交,产品库提交,产品图片上传子模块.比较不同软件商这一模块的强弱,主要要看B2B站点和分类信息站点的数量和质量,注册的成功率这

Android编程调用Camera和相册功能详解

本文实例讲述了Android编程调用Camera和相册功能.分享给大家供大家参考,具体如下: xml: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="

Android编程实现的微信支付功能详解【附Demo源码下载】

本文实例讲述了Android编程实现的微信支付功能.分享给大家供大家参考,具体如下: 最近公司弄Ionic框架,项目中需要微信支付,无奈,把我调过去弄,期间也是几近崩溃,好在皇天不负有心人,在看别人的文档,终于是在项目中集成了微信支付,下面作为一个小白的我,想要把我的经验分享给大家,希望对大家有所帮助. 先给一个可用的demo吧(运行前先看txt文件) demo代码点击此处本站下载. 这个demo是基于eclipse开发的,博主也在Android Studio开发过微信支付,原理都是一样的,大家

Android 混淆代码详解及实例_Android

为了防止自己的劳动成果被别人窃取,混淆代码能有效防止被反编译,下面来总结以下混淆代码的步骤: 1. 大家也许都注意到新建一个工程会看到项目下边有这样proguard-project.txt一个文件,这个对混淆代码很重要,如果你不小心删掉了,没关系,从其他地方拷贝一个过来 2. 最重要的就是在proguard-project.txt添加混淆的申明了:  a. 把所有你的jar包都申明进来,例如:  -libraryjars libs/apns_1.0.6.jar  -libraryjars lib

Android4.4 访问外部存储详解及实例_Android

Android4.4  访问外部存储 在Android 4.4系统中,外置存储卡(SD卡)被称为二级外部存储设备(secondary storage),应用程序已无法往外置存储卡(SD卡)写入数据,并且WRITE_EXTERNAL_STORAGE只为设备上的主要外部存储(primary storage)授予写权限,对于其他外部存储,其上的文件属性都改为基于文件夹结构,应用无需获取WRITE_EXTERNAL_STORAGE权限,但可以管理与自己包名相关的文件夹.举例来说,如果应用的包名是com.