欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android实现视频弹幕功能

程序员文章站 2023-02-19 14:50:15
本文实例为大家分享了android视频弹幕的具体代码,供大家参考,具体内容如下 效果图: 上图:代码随机生成的弹幕及弹幕输入栏 下图:绿色框的弹幕为用户手动添加发送的弹幕...

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

效果图:

Android实现视频弹幕功能

Android实现视频弹幕功能

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

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

1.准备工作

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

Android实现视频弹幕功能

需要将视频设置为横屏播放,即往配置文件中添加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中

Android实现视频弹幕功能

注: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);
    }
  }
}

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