当前位置: 移动技术网 > IT编程>移动开发>Android > Android实现视频弹幕功能

Android实现视频弹幕功能

2020年03月09日  | 移动技术网IT编程  | 我要评论

dopad,突袭国庆日 豆瓣,中国方言

本文实例为大家分享了android视频弹幕的具体代码,供大家参考,具体内容如下

效果图:

上图:代码随机生成的弹幕及弹幕输入栏

下图:绿色框的弹幕为用户手动添加发送的弹幕

1.准备工作

准备一个视频文件,将该视频文件放到res/raw目录下。

需要将视频设置为横屏播放,即往配置文件中添加android:screenorientation="landscape":

<activity android:name=".mainactivity"
  android:configchanges="keyboardhidden|orientation|screenlayout|screensize"
  android:screenorientation="landscape">
  <intent-filter>
    <action android:name="android.intent.action.main" />
    <category android:name="android.intent.category.launcher" />
  </intent-filter>
</activity>

这里用到了哔哩哔哩开源的弹幕效果库danmakuflamemaster,需要配置到模块的build.gradle的dependencies中

注:danmakuflamemaster的版本最好使用在0.9以上,否则会存在一些弹幕bug

2.布局

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

<?xml version="1.0" encoding="utf-8"?>
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent" android:layout_height="match_parent"
  android:background="#000000">
 
  <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/danmu"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
  <linearlayout
    android:id="@+id/operate_layout"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:layout_alignparentbottom="true"
    android:visibility="gone">
    <edittext
      android:id="@+id/edit"
      android:layout_width="0dp"
      android:layout_height="match_parent"
      android:layout_weight="1"
      android:layout_marginleft="50dp"
      android:textcolor="#ffffff"
      android:imeoptions="flagnoextractui"
      />
    <button
      android:layout_width="wrap_content"
      android:layout_height="match_parent"
      android:id="@+id/send"
      android:textsize="20sp"
      android:background="#00000000"
      android:textcolor="#ffffff"
      android:text="发送"/>
  </linearlayout>
</relativelayout>

3.视频弹幕的实现

<1>播放视频使用videoview来进行播放;

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

<3>需要在onpause()、onresume()、ondestroy()方法中执行一些操作,以保证danmakuview的资源可以得到释放。

下面附上完整代码

package com.mega.mydanmudemo;
 
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;
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 showdanma;
  private videoview mvideoview;
  private danmakuview mdanmu;
  private basedanmakuparser mbasedanmakuparser = new basedanmakuparser() {//弹幕解析器
    @override
    protected idanmakus parse() {
      return new danmakus();
    }
  };
  private danmakucontext danmakucontext;
 
  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.main);
    init();
    setonlistener();
  }
 
  /***
   * 一些初始化工作
   */
  private void init() {
    string uri = "android.resource://" + getpackagename() + "/" + r.raw.danmu;
    mvideoview = (videoview)findviewbyid(r.id.video_view);
    mvideoview.setvideopath(uri);
    mvideoview.start();
 
    mdanmu = (danmakuview)findviewbyid(r.id.danmu);
    mdanmu.enabledanmakudrawingcache(true);
    danmakucontext = danmakucontext.create();
    danmakucontext.setscaletextsize(1.1f);
    mdanmu.prepare(mbasedanmakuparser,danmakucontext);
  }
 
  /***
   * 弹幕的准备工作,发送按钮监听。。
   */
  private void setonlistener(){
 
    mdanmu.setcallback(new drawhandler.callback() {
      @override
      public void prepared() {
        showdanma = true;
        mdanmu.start();//启动弹幕
        generatesomedanmu();
      }
 
      @override
      public void updatetimer(danmakutimer timer) {
 
      }
 
      @override
      public void danmakushown(basedanmaku danmaku) {
 
      }
 
      @override
      public void drawingfinished() {
 
      }
    });
 
    final linearlayout operate_view = (linearlayout)findviewbyid(r.id.operate_layout);
    button send = (button)findviewbyid(r.id.send);
    final edittext edittext = (edittext)findviewbyid(r.id.edit);
 
    mdanmu.setonclicklistener(new view.onclicklistener() {
      @override
      public void onclick(view view) {
        if (operate_view.getvisibility() == view.gone){
          operate_view.setvisibility(view.visible);
        }else{
          operate_view.setvisibility(view.gone);
        }
      }
    });
    send.setonclicklistener(new view.onclicklistener() {
      @override
      public void onclick(view view) {
        string content = edittext.gettext().tostring();
        if (!textutils.isempty(content)){
          inputmethodmanager imm = (inputmethodmanager) getsystemservice(context.input_method_service);
          imm.hidesoftinputfromwindow(edittext.getwindowtoken(),0);
          adddamu(content,true);
          edittext.settext("");
          operate_view.setvisibility(view.gone);
        }
      }
    });
 
    getwindow().getdecorview().setonsystemuivisibilitychangelistener(new view.onsystemuivisibilitychangelistener() {
      @override
      public void onsystemuivisibilitychange(int visibility) {
        if (visibility == view.system_ui_flag_visible){
          onwindowfocuschanged(true);
        }
      }
    });
  }
 
  /***
   * 随机产生一些弹幕
   */
  private void generatesomedanmu() {
    new thread(new runnable() {
      @override
      public void run() {
        while (showdanma){
          int time = new random().nextint(300);
          string content = "" + time;
          adddamu(content,false);
          try {
            thread.sleep(time);
          }catch (exception e){
            e.printstacktrace();
          }
        }
      }
    }).start();
  }
 
  /***
   * 添加弹幕的方法
   * @param content 弹幕的内容
   * @param isself 是否是用户发送的弹幕
   */
  private void adddamu(string content,boolean isself) {
    basedanmaku danmaku = danmakucontext.mdanmakufactory.createdanmaku(basedanmaku.type_scroll_rl);
    danmaku.text = content;
    danmaku.padding = 5;
    danmaku.priority = 0;
    danmaku.textsize = sp2px(20);
    danmaku.settime(mdanmu.getcurrenttime());
    danmaku.textcolor = color.argb(new random().nextint(256), new random().nextint(256),
        new random().nextint(256),new random().nextint(256));
    if (isself){
      danmaku.bordercolor = color.green;
    }
    mdanmu.adddanmaku(danmaku);
  }
  
  private float sp2px(int i) {
    final float fontscale = getresources().getdisplaymetrics().scaleddensity;
    return (int)(i* fontscale +0.5f);
  }
 
  @override
  protected void onpause() {
    super.onpause();
    if (mdanmu!= null && mdanmu.isprepared()){
      mdanmu.pause();
    }
  }
 
  @override
  protected void onresume() {
    super.onresume();
    if (mdanmu!=null&& mdanmu.isprepared()&& mdanmu.ispaused()){
      mdanmu.resume();
    }
  }
 
  @override
  protected void ondestroy() {
    super.ondestroy();
    showdanma = false;
    if (mdanmu != null){
      mdanmu.release();
      mdanmu = null;
    }
  }
 
  @override
  public void onwindowfocuschanged(boolean hasfocus) {
    super.onwindowfocuschanged(hasfocus);
    if (hasfocus && build.version.sdk_int>=19){
      view deview = getwindow().getdecorview();
      deview.setsystemuivisibility(view.system_ui_flag_layout_stable
      |view.system_ui_flag_hide_navigation
      |view.system_ui_flag_fullscreen
      |view.system_ui_flag_layout_hide_navigation
      |view.system_ui_flag_layout_fullscreen
      |view.system_ui_flag_immersive_sticky);
    }
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网