天天看点

【Android 常见控件使用】DanmakuView(弹幕)

文章目录

  • ​​弹幕使用​​
  • ​​一、准备工作​​
  • ​​二、任务分析与实施​​
  • ​​1.MainActitvity 中获取界面控件​​
  • ​​2.播放视频​​
  • ​​3.初始化弹幕​​
  • ​​4.随机生成与添加弹幕​​
  • ​​5.效果展示​​

弹幕使用

一、准备工作

【Android 常见控件使用】DanmakuView(弹幕)
  • 导入播放的视频
  • 导入基本组件:VideoView、DanmakuView、EditText、Button

​​返回顶部​​

二、任务分析与实施

当点击弹幕界面的时候,界面底部会弹出一个输入框和一个发送按钮,当输入文字并点击按钮后,弹幕会出现一个蓝色框,框中显示刚刚发送的文字;当再次点击弹幕时,界面底部的输入框和按钮消失。

1.MainActitvity 中获取界面控件

public class MainActivity extends AppCompatActivity {

    // 获取控件
    private EditText input;
    private Button submit;
    private DanmakuView danmaku;
    private VideoView videoView;
    private DanmakuContext danmakuContext;
    private LinearLayout layout;
    private boolean showDanmaku;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化界面控件
        layout = findViewById(R.id.layout);
        input = findViewById(R.id.input);
        submit = findViewById(R.id.submit);
        danmaku = findViewById(R.id.danmaku);
        videoView = findViewById(R.id.videoView);
        
    }   
}      

​​返回顶部​​

2.播放视频

  • 在MAinActivity中创建playVido方法用于播放视频文件
// 播放视频
private void playVideo() {
    // 获取视频路径
    String uri = "android.resource://" + getPackageName() + "/" + R.raw.speed;
    //String uri = "G:\\Projects\\AndroidStudioProjects\\Barrage\\app\\src\\main\\res\\raw\\sun.mp4";
    if (uri != null) {
        // 配置到 VideoView 组件中
        videoView.setVideoURI(Uri.parse(uri));
        videoView.start();
    } else {
        // 将背景设置为透明
        videoView.getBackground().setAlpha(0);
    }
}      

​​返回顶部​​

3.初始化弹幕

  • 在MAinActivity中创建一个initDanmaku方法,用于初始化弹幕并调用弹幕的随机生成与添加方法
// 弹幕解析器
private BaseDanmakuParser parser = new BaseDanmakuParser() {
    @Override
    protected IDanmakus parse() {
        return new Danmakus();
    }
};

// 初始化弹幕
private void initDanmaku(){
    danmaku.setCallback(new DrawHandler.Callback() {
        @Override
        public void prepared() {
            showDanmaku = true;
            danmaku.start();    // 开始弹幕
            generateDanmakus(); // 随机生成弹幕的方法
        }
        @Override
        public void updateTimer(DanmakuTimer timer) {
        }
        @Override
        public void danmakuShown(BaseDanmaku danmaku) {
        }
        @Override
        public void drawingFinished() {
        }
    });
    // 创建 DanmakuContext 上下文对象
    danmakuContext = DanmakuContext.create();
    // 开始缓存
    danmaku.enableDanmakuDrawingCache(true);
    // 弹幕view准备  --- 传入解析器
    danmaku.prepare(parser,danmakuContext);
    // 弹幕组件点击事件
    danmaku.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (layout.getVisibility() == View.GONE){
                layout.setVisibility(View.VISIBLE);
            } else {
                layout.setVisibility(View.GONE);
            }
        }
    });
    // 提交按钮点击事件
    submit.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            String content = input.getText().toString();
            if (!TextUtils.isEmpty(content)){
                addDanmaku(content,true);     // 添加一条弹幕
                input.setText("");
            }
        }
    });
}      

​​返回顶部​​

4.随机生成与添加弹幕

generateDanmakus():随机生成弹幕

addDanmaku():添加弹幕至弹幕组件

// 添加弹幕
private void addDanmaku(String content, boolean border) {
    // 创建弹幕对象,设置从右向左滚动
    BaseDanmaku baseDanmaku = danmakuContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
    baseDanmaku.text = content;     // 设置内容
    baseDanmaku.padding = 6;        // 设置边距
    baseDanmaku.textSize = 25;      // 设置弹幕字体大小
    baseDanmaku.textColor = Color.WHITE;            // 设置弹幕字体颜色
    baseDanmaku.setTime(danmaku.getCurrentTime());  // 设置当前时间
    if (border){
        baseDanmaku.borderColor = Color.BLUE;       // 设置边框颜色
    }
    // 添加弹幕至弹幕视图组件中
    danmaku.addDanmaku(baseDanmaku);
}

// 随机生成弹幕
private void generateDanmakus() {
    // 启用线程随机生成弹幕
    new Thread(new Runnable() {
        @Override
        public void run() {
            while (showDanmaku) {
                int num = new Random().nextInt(300);
                String content = ""+num;
                addDanmaku(content,false);
                try {
                    Thread.sleep(num);
                } catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }).start();
}      

​​返回顶部​​

5.效果展示

【Android 常见控件使用】DanmakuView(弹幕)
package com.example.barrage;

import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.net.Uri;
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 AppCompatActivity {

    // 获取控件
    private EditText input;
    private Button submit;
    private DanmakuView danmaku;
    private VideoView videoView;
    private DanmakuContext danmakuContext;
    private LinearLayout layout;
    private boolean showDanmaku;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化界面控件
        layout = findViewById(R.id.layout);
        input = findViewById(R.id.input);
        submit = findViewById(R.id.submit);
        danmaku = findViewById(R.id.danmaku);
        videoView = findViewById(R.id.videoView);

        // 调用方法
        playVideo();
        initDanmaku();
    }

    // 播放视频
    private void playVideo() {
        // 获取视频路径
        String uri = "android.resource://" + getPackageName() + "/" + R.raw.speed;
        //String uri = "G:\\Projects\\AndroidStudioProjects\\Barrage\\app\\src\\main\\res\\raw\\sun.mp4";
        if (uri != null) {
            // 配置到 VideoView 组件中
            videoView.setVideoURI(Uri.parse(uri));
            videoView.start();
        } else {
            // 将背景设置为透明
            videoView.getBackground().setAlpha(0);
        }
    }

    // 弹幕解析器
    private BaseDanmakuParser parser = new BaseDanmakuParser() {
        @Override
        protected IDanmakus parse() {
            return new Danmakus();
        }
    };

    // 初始化弹幕
    private void initDanmaku(){
        danmaku.setCallback(new DrawHandler.Callback() {
            @Override
            public void prepared() {
                showDanmaku = true;
                danmaku.start();    // 开始弹幕
                generateDanmakus(); // 随机生成弹幕的方法
            }
            @Override
            public void updateTimer(DanmakuTimer timer) {
            }
            @Override
            public void danmakuShown(BaseDanmaku danmaku) {
            }
            @Override
            public void drawingFinished() {
            }
        });
        // 创建 DanmakuContext 上下文对象
        danmakuContext = DanmakuContext.create();
        // 开始缓存
        danmaku.enableDanmakuDrawingCache(true);
        // 弹幕view准备  --- 传入解析器
        danmaku.prepare(parser,danmakuContext);
        // 弹幕组件点击事件
        danmaku.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (layout.getVisibility() == View.GONE){
                    layout.setVisibility(View.VISIBLE);
                } else {
                    layout.setVisibility(View.GONE);
                }
            }
        });
        // 提交按钮点击事件
        submit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String content = input.getText().toString();
                if (!TextUtils.isEmpty(content)){
                    addDanmaku(content,true);     // 添加一条弹幕
                    input.setText("");
                }
            }
        });
    }

    // 添加弹幕
    private void addDanmaku(String content, boolean border) {
        // 创建弹幕对象,设置从右向左滚动
        BaseDanmaku baseDanmaku = danmakuContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
        baseDanmaku.text = content;     // 设置内容
        baseDanmaku.padding = 6;        // 设置边距
        baseDanmaku.textSize = 25;      // 设置弹幕字体大小
        baseDanmaku.textColor = Color.WHITE;            // 设置弹幕字体颜色
        baseDanmaku.setTime(danmaku.getCurrentTime());  // 设置当前时间
        if (border){
            baseDanmaku.borderColor = Color.BLUE;       // 设置边框颜色
        }
        // 添加弹幕至弹幕视图组件中
        danmaku.addDanmaku(baseDanmaku);
    }

    // 随机生成弹幕
    private void generateDanmakus() {
        // 启用线程随机生成弹幕
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (showDanmaku) {
                    int num = new Random().nextInt(300);
                    String content = ""+num;
                    addDanmaku(content,false);
                    try {
                        Thread.sleep(num);
                    } catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (danmaku!=null && danmaku.isPrepared()){
            danmaku.pause();
        }
    }

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

    @Override
    protected void onDestroy() {
        super.onDestroy();
        showDanmaku = false;
        if (danmaku!=null){
            danmaku.release();
            danmaku= null;
        }
    }
}      
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <VideoView
        android:id="@+id/videoView"
        android:layout_width="match_parent"
        android:layout_height="262dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        tools:ignore="MissingConstraints"
        tools:layout_editor_absoluteY="30dp" />

    <master.flame.danmaku.ui.widget.DanmakuView
        android:id="@+id/danmaku"
        android:layout_width="match_parent"
        android:layout_height="122dp"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:layout_marginStart="0dp" />

    <!-- 按钮和文本编辑框放在同一布局中,实现显示隐藏功能 -->
    <LinearLayout
        android:id="@+id/layout"
        android:layout_width="372dp"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginStart="20dp"
        android:layout_marginTop="295dp"
        android:visibility="gone">
        <EditText
            android:id="@+id/input"
            android:layout_width="233dp"
            android:layout_height="match_parent"
            android:layout_marginEnd="20dp"
            android:hint="请输入弹幕" />
        <Button
            android:id="@+id/submit"
            android:layout_width="104dp"
            android:layout_height="match_parent"
            android:layout_marginEnd="10dp"
            android:text="发送"
            android:textSize="20dp">
        </Button>
    </LinearLayout>

</RelativeLayout>