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

本文详细介绍了如何使用SurfaceView进行视频播放,并实现弹幕功能。通过继承SurfaceView并实现SurfaceHolder.Callback接口,监听surface生命周期。在surfaceCreated方法中启动绘图线程,使用lockCanvas和unlockCanvasAndPost进行绘制。此外,为了实现弹幕显示,将弹幕SurfaceView设置为置顶且背景透明。同时,通过定时器和歌词时间集合动态匹配当前歌词,实现在SurfaceView上的滚动展示。
摘要由CSDN通过智能技术生成

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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值