专栏首页恩蓝脚本SurfaceView播放视频发送弹幕并实现滚动歌词

SurfaceView播放视频发送弹幕并实现滚动歌词

本文实例为大家分享了SurfaceView播放视频发送弹幕,并实现滚动歌词,供大家参考,具体内容如下

SurfaceView使用步骤

使用SurfaceView的步骤:

  • 首先要继承SurfaceView,实现SurfaceHolder.Callback接口。
  • 重写方法:surfaceChanged:surface大小或格式发生变化时触发,在surfaceCreated调用后该函数至少会被调用一次。
  • surfaceCreated:Surface创建时触发,一般在这个函数开启绘图线程(新的线程,不要再这个线程中绘制Surface)。
  • surfaceDestroyed:销毁时触发,一般不可见时就会销毁。
  • 利用getHolder()获取SurfaceHolder对象,调用SurfaceHolder.addCallback添加回调
  • SurfaceHolder.lockCanvas 获取Canvas对象并锁定画布,调用Canvas绘图,SurfaceHolder.unlockCanvasAndPost 结束锁定画布,提交改变。

SurfaceHolder

SurfaceHolder回调自己的三个生命周期:

  • surfaceCreated(SurfaceHolder holder)创建时
  • surfaceChanged(SurfaceHolder holder, int format, int width, int height)改变时
  • surfaceDestroyed(SurfaceHolder holder)销毁时

SurfaceView播放视频并可以发送弹幕

需要准备两个SurfaceView,一个是负责播放视频,一个负责展示弹幕。弹幕是展示在视频上面的,所以我们要给展示弹幕的SurfaceView设置两个方法: surfaceView_danmu.setZOrderOnTop(true); ——置于上方 surfaceView_danmuHolder.setFormat(PixelFormat.TRANSPARENT); ——背景透明

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
public static final int PROGRESS = 101;
SurfaceView surfaceView,surfaceView_danmu;
SurfaceHolder surfaceHolder,surfaceView_danmuHolder;
MediaPlayer mediaPlayer = new MediaPlayer();
String path = "/sdcard/aa.mp4";
SeekBar seekBar;
Timer timer;
EditText editText;
Button button,bt_start,bt_stop;
int x = 0;
ArrayList<DanMu  list = new ArrayList< ();
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == PROGRESS){
seekBar.setProgress((Integer) msg.obj);
mediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
@Override
public void onSeekComplete(MediaPlayer mp) {
Toast.makeText(MainActivity.this, "播放完毕!", Toast.LENGTH_SHORT).show();
}
});
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceView = findViewById(R.id.sufaceview);
surfaceView_danmu = findViewById(R.id.sufaceview_danmu);
editText = findViewById(R.id.et);
button = findViewById(R.id.bt_send);
seekBar = findViewById(R.id.bar);
bt_start = findViewById(R.id.bt_start);
bt_stop = findViewById(R.id.bt_stop);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceView_danmuHolder = surfaceView_danmu.getHolder();
surfaceView_danmuHolder.addCallback(this);
surfaceView_danmu.setZOrderOnTop(true);
surfaceView_danmuHolder.setFormat(PixelFormat.TRANSPARENT);
if (mediaPlayer!=null) {
try {
mediaPlayer.setDataSource(path);
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer.start();
int duration = mediaPlayer.getDuration();
seekBar.setMax(duration);
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
int currentPosition = mediaPlayer.getCurrentPosition();
Message message = Message.obtain();
message.what = PROGRESS;
message.obj = currentPosition;
handler.sendMessage(message);
}
},0,1000);
}
});
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
int progress = seekBar.getProgress();
mediaPlayer.seekTo(progress);
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String s = editText.getText().toString();
int y= (int) (Math.random()*300);
list.add(new DanMu(0,y,s,Color.RED));
}
});
bt_start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mediaPlayer.start();
}
});
bt_stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mediaPlayer.pause();
}
});
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (holder == surfaceHolder) {
mediaPlayer.setDisplay(holder);
}else if (holder == surfaceView_danmuHolder) {
new MyDanMuThread().start();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
class MyDanMuThread extends Thread {
@Override
public void run() {
super.run();
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setTextSize(40);
while (true) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
Canvas canvas = surfaceView_danmuHolder.lockCanvas();
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
for (int i=0;i<list.size();i++) {
DanMu danMu = list.get(i);
x = danMu.getX();
danMu.setX(x+=10);
canvas.drawText(danMu.getText(),danMu.getX(),danMu.getY(),paint);
}
surfaceView_danmuHolder.unlockCanvasAndPost(canvas);
}
}
}
}

实现滚动歌词

要准备一个装有时间和歌词的集合,准备一个Timer计时器和一个该展示第几个歌词。每隔一秒去拿该歌词的下一个歌词时间与进度匹配,如果进度 =该时间,那么就画该歌词在SurfaceView上;<则不画该歌词

一定要写SD卡读写权限!!!!!

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback{
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
MediaPlayer mediaPlayer = new MediaPlayer();
ArrayList<Music  list=new ArrayList< ();
Timer timer;
int count = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceView = findViewById(R.id.sv);
surfaceHolder=surfaceView.getHolder();
surfaceHolder.addCallback(this);
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
int currentPosition = mediaPlayer.getCurrentPosition();
if(list.size() 0){
if(currentPosition =list.get(count+1).getTime()){
count++;
}
}
}
},0,500);
try {
mediaPlayer.setDataSource("/sdcard/凤凰传奇 - 最炫民族风(Live).mp3");
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer.start();
}
});
} catch (IOException e) {
e.printStackTrace();
}
try {
StringBuffer stringBuffer = new StringBuffer();
FileInputStream fileInputStream = new FileInputStream("/sdcard/最炫民族风");
byte[] bytes = new byte[1024];
int len = 0;
while ((len=fileInputStream.read(bytes))!=-1) {
stringBuffer.append(new String(bytes,0,len));
}
Gson gson = new Gson();
JavaBean javaBean = gson.fromJson(stringBuffer.toString(), JavaBean.class);
JavaBean.LrcBean lrc = javaBean.getLrc();
String lyric = lrc.getLyric();
String[] split = lyric.split("\n");
for(int i=0;i<split.length;i++){
String trim = split[i].trim();
String[] split1 = trim.split("]");
if(split.length =2){
String s = split1[0];
String substring1 = s.substring(1, 3);
String substring2 = s.substring(4, 6);
String substring3 = s.substring(7, 10);
long start = Integer.parseInt(substring1)*60*1000+Integer.parseInt(substring2)*1000+Integer.parseInt(substring3);
String text = split1[1];
list.add(new Music(text,start));
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
new MyThread().start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
class MyThread extends Thread {
@Override
public void run() {
super.run();
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setTextSize(50);
while (true){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
Canvas canvas = surfaceHolder.lockCanvas();
if(canvas==null){
break;
}
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
if(list.size() 0){
canvas.drawText(list.get(count).getTitle(),100,100,paint);
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android使用Realm数据库实现App中的收藏功能(代码详解)

    App数据持久化功能是每个App必不可少的功能,而Android最常用的数据持久化方式主要有以下的五种方式:

    砸漏
  • SwipeRefreshLayout+RecyclerView实现上拉刷新和下拉刷新功能

    SwipeRefreshLayout 是谷歌公司推出的用于下拉刷新的控件,SwipeRefreshLayout已经被放到了sdk中,在Version 19.1之...

    砸漏
  • Android EditText 监听用户输入完成的实例

    我们都知道, Android EditText输入框,并没有监听用户输入完成的功能,需要我们自己实现。 下面是实现的方法,仅供参考:

    砸漏
  • 【JAVA】多线程学习2模拟一个银行存款的程序

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY 版权协议,转载请附上原文出处链接和本声明。

    韩旭051
  • Android registerActivityLifecycleCallbacks 使用

    使用这个类,我们可以很方便的监听到 Activity 的状态,从而可以判断 APP 是否在前台或者后台等。

    Vance大飞
  • 编写高性能的Java代码需要注意的4个问题

    ThreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal没有外部强引用来引用它,那么系统 GC 的时候,这个Th...

    宜信技术学院
  • Android Rxjava :最简单&全面背压讲解 (Flowable)

    阅读本文需要对Rxjava了解,如果还没有了解或者使用过Rxjava的兄die们,推荐观看 Android Rxjava:图解不一样的诠释 进行学习。

    Android技术干货分享
  • new ScalarHandler()-->返回值为long,不能用int接收!!!

    qr.query()返回object类型 ,先转成 ScalarHandler的Long类型 然后 在转为 int类型,之前我直接就转成int类型所以就GG了呱...

  • Java多线程JUC

    1. volatile 关键字 多线程访问的时候,一个比较严重的问题就是内存不可见,其实在内存访问的时候每一个线程都有一个自己的缓冲区,每次在做修改的时候都是从...

    lwen
  • 多线程之策略模式

    今天给各位分享一种Java23种设计模式中最常见的设计模式--策略模式。为什么将策略模式和多线程绑在一起呢,不知道各位有没有注意过我们在进行多线程编程的时候,创...

    赵小忠

扫码关注云+社区

领取腾讯云代金券