本文实例为大家分享了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);
      }
    }
  }
}

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

SurfaceView播放视频发送弹幕并实现滚动歌词的更多相关文章

  1. android – 从自定义SurfaceView获取位图

    我在一个扩展表面视图并实现runnable的类中有这个代码我能够使用该类基本上允许您使用不同的颜色等绘制到画布.我正在尝试获得一种方法,允许我在绘制图像后保存图像,这是方法.无论我做什么,我只是得到一个黑色的图像,没有任何东西.有任何想法吗?

  2. Android在相机预览上绘制

    如何在不分层SurfaceView的情况下执行此操作?解决方法你不能在具有Type.PUSH_BUFFERS的SurfaceView上进行locK和绘图.您必须在Z方向上创建原始视图上方的另一个视图,并在该视图中的SurfaceView上绘制.因此,在main.xml中,在FrameLayout中的原始视图下创建一个自定义视图.在活动视图中创建和处理SurfaceView.将此视图添加到相机预览显示中.通过SurfaceHolder启动自定义视图.在此视图中可以在画布上锁定和绘制.

  3. Android Surfaceview线程和内存泄漏

    我在android中创建一个游戏,我注意到游戏有内存泄漏.我设法将内存泄漏隔离到一个较小的应用程序,以便我可以看到很好的尝试和解决,如何解决它.该应用程序使用一个surfaceview作为其视图,并附加一个线程,以便完成所有绘图到屏幕.当我开始一个新活动并关闭我当前正在使用的活动时,会发生内存泄漏.当我在我的测试应用程序上执行内存转储时,我可以看到这一点,因为它只是打开并关闭一个活动(活动a–>活

  4. android – 在SurfaceView加载Camera Preview时显示我的布局

    我在BG线程中创建Cameraview的解决方案解决了无响应问题.但未能在SurfaceView中显示Camera输出.解决方案是从xml中删除SurfaceView.这将立即启动您的活动.加载新的“活动”布局后,可以以编程方式将新的SurfaceView添加到屏幕上.当然,这也需要时间,但您的UI会快速切换到新活动,并且您可以在SurfaceView和Camera加载时显示加载程序!

  5. android – 设置Surface View的背景颜色

    我想将表面视图的背景颜色设置为我的相机表面视图.我使用this来实现相同的功能.但这个例子并不完整.任何人都可以帮助我一些其他有用的链接.谢谢解决方法有一个解决方法来做到这一点.>为surfaceview添加父视图组,将背景颜色设置为此视图组而不是surfaceview;>为SurfaceView实例添加以下内容;现在你得到你想要的背景颜色,而surfaceview是tanslucent.

  6. Media Recorder在Android摄像头启动失败

    我正在制作视频录制应用程序,我想在其中显示预览,当用户点击录制按钮时,它开始录制,当用户点击停止按钮时,它停止录制.我在我的表面上进行了视频预览,但是当我按下开始按钮时,它会出现错误“MEDIA.RECORDER.START(NativeMEthod)”.这是我的代码请帮帮我们.}记录是解决方法我发现这个解决方案和它的工作正常,我解决了这个问题:)对于2.3android:只是改变:至:

  7. android – surfaceView.getHolder没有返回SurfaceHolder

    我正在尝试编写使用相机的应用程序.在尝试获取我最终传递给启动摄像头的surfaceCreated()的surfaceHolder时,我得到一个NullPointerException.getHolder()返回NULL时有什么情况吗?谢谢.解决方法开始一个新的答案,希望更清楚.同样,我认为根本问题是你在onCreate和onResume上做的事情的数量.我认为您遇到的根本问题是视图/活动生命周期的

  8. android – SurfaceView使用自定义相机缩放IN和OUT功能

    我已经编写了使用CustomCamera的代码,为此我使用的是SurfaceView,现在我想知道如果我需要实现ZoomIN和OUT功能,我从未使用过这种应用程序.我的代码,我用来创建自定义相机,见下文:MainActivity.java:-activity_main.xml中:–解决方法下面是缩放功能的示例代码.请尝试它是否可以帮助您:

  9. android – TextureView中的抗锯齿

    我尝试使用SurfaceView和TextureView播放相同的视频,并注意到使用TextureView渲染的图像比使用SurfaceView更具别名.这是什么原因?有没有办法配置TextureView的渲染看起来更好?TextureView的用法如下:而对于SurfaceView:解决方法好吧,似乎在TextureView上应用缩放就可以实现我正在寻找的“平滑”效果.这听起来像是一个奇怪的黑客……但它确实有效.挖掘改变渲染方面的缩放比例会很有趣……

  10. android – Gradient在SurfaceView中显示为带状,但在普通视图中看起来非常流畅

    崔佛解决方法最后通过将其添加到SurfaceView的构造函数中找到了解决方案:

随机推荐

  1. Flutter 网络请求框架封装详解

    这篇文章主要介绍了Flutter 网络请求框架封装详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Android单选按钮RadioButton的使用详解

    今天小编就为大家分享一篇关于Android单选按钮RadioButton的使用详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

  3. 解决android studio 打包发现generate signed apk 消失不见问题

    这篇文章主要介绍了解决android studio 打包发现generate signed apk 消失不见问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  4. Android 实现自定义圆形listview功能的实例代码

    这篇文章主要介绍了Android 实现自定义圆形listview功能的实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. 详解Android studio 动态fragment的用法

    这篇文章主要介绍了Android studio 动态fragment的用法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. Android用RecyclerView实现图标拖拽排序以及增删管理

    这篇文章主要介绍了Android用RecyclerView实现图标拖拽排序以及增删管理的方法,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下

  7. Android notifyDataSetChanged() 动态更新ListView案例详解

    这篇文章主要介绍了Android notifyDataSetChanged() 动态更新ListView案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下

  8. Android自定义View实现弹幕效果

    这篇文章主要为大家详细介绍了Android自定义View实现弹幕效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. Android自定义View实现跟随手指移动

    这篇文章主要为大家详细介绍了Android自定义View实现跟随手指移动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Android实现多点触摸操作

    这篇文章主要介绍了Android实现多点触摸操作,实现图片的放大、缩小和旋转等处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部