SurfaceView 視頻發(fā)送彈幕并實(shí)現(xiàn)滾動(dòng)歌詞
本文實(shí)例為大家分享了SurfaceView 視頻發(fā)送彈幕,并實(shí)現(xiàn)滾動(dòng)歌詞,供大家參考,具體內(nèi)容如下
SurfaceView使用步驟
使用SurfaceView的步驟:
- 首先要繼承SurfaceView,實(shí)現(xiàn)SurfaceHolder.Callback接口。
- 重寫方法:surfaceChanged:surface大小或格式發(fā)生變化時(shí)觸發(fā),在surfaceCreated調(diào)用后該函數(shù)至少會(huì)被調(diào)用一次。
- surfaceCreated:Surface創(chuàng)建時(shí)觸發(fā),一般在這個(gè)函數(shù)開啟繪圖線程(新的線程,不要再這個(gè)線程中繪制Surface)。
- surfaceDestroyed:銷毀時(shí)觸發(fā),一般不可見時(shí)就會(huì)銷毀。
- 利用getHolder()獲取SurfaceHolder對象,調(diào)用SurfaceHolder.addCallback添加回調(diào)
- SurfaceHolder.lockCanvas 獲取Canvas對象并鎖定畫布,調(diào)用Canvas繪圖,SurfaceHolder.unlockCanvasAndPost 結(jié)束鎖定畫布,提交改變。
SurfaceHolder
SurfaceHolder回調(diào)自己的三個(gè)生命周期:
- surfaceCreated(SurfaceHolder holder)創(chuàng)建時(shí)
- surfaceChanged(SurfaceHolder holder, int format, int width, int height)改變時(shí)
- surfaceDestroyed(SurfaceHolder holder)銷毀時(shí)
SurfaceView 視頻并可以發(fā)送彈幕
需要準(zhǔn)備兩個(gè)SurfaceView,一個(gè)是負(fù)責(zé) 視頻,一個(gè)負(fù)責(zé)展示彈幕。彈幕是展示在視頻上面的,所以我們要給展示彈幕的SurfaceView設(shè)置兩個(gè)方法:
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); } } } }
實(shí)現(xiàn)滾動(dòng)歌詞
要準(zhǔn)備一個(gè)裝有時(shí)間和歌詞的集合,準(zhǔn)備一個(gè)Timer計(jì)時(shí)器和一個(gè)該展示第幾個(gè)歌詞。每隔一秒去拿該歌詞的下一個(gè)歌詞時(shí)間與進(jìn)度匹配,如果進(jìn)度>=該時(shí)間,那么就畫該歌詞在SurfaceView上;<則不畫該歌詞
一定要寫SD卡讀寫權(quán)限!?。。。?/span>
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/鳳凰傳奇 - 最炫民族風(fēng)(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/最炫民族風(fēng)"); 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); } } } }
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持我們。
上一篇:Android WebView實(shí)現(xiàn)頂部進(jìn)度條
欄 目:Android
下一篇:Android實(shí)現(xiàn)視頻彈幕功能
本文標(biāo)題:SurfaceView 視頻發(fā)送彈幕并實(shí)現(xiàn)滾動(dòng)歌詞
本文地址:http://mengdiqiu.com.cn/a1/Android/9041.html
您可能感興趣的文章
- 01-10Android MediaPlayer 音頻的方式
- 01-10Android使用MediaPlayer和TextureView實(shí)現(xiàn)視頻無縫切換
- 01-10Android MediaPlayer 音頻倍速 調(diào)整 速度問題
- 01-10Android使用MediaCodec將攝像頭采集的視頻編碼為h264
- 01-10兩個(gè)surfaceView實(shí)現(xiàn)切換效果
- 01-10Android基于騰訊云實(shí)時(shí)音視頻仿微信視頻通話最小化懸浮
- 01-10Android采用消息推送實(shí)現(xiàn)類似微信視頻接聽
- 01-10android使用surfaceview+MediaPlayer 視頻
- 01-10Android實(shí)現(xiàn)視頻彈幕功能
- 01-10Android使用SoundPool實(shí)現(xiàn) 音效


閱讀排行
本欄相關(guān)
- 01-10Android自定義View之繪制圓形頭像功能
- 01-10Android實(shí)現(xiàn)雙擊返回鍵退出應(yīng)用實(shí)現(xiàn)方
- 01-10android實(shí)現(xiàn)簡單計(jì)算器功能
- 01-10android實(shí)現(xiàn)記住用戶名和密碼以及自動(dòng)
- 01-10C++自定義API函數(shù)實(shí)現(xiàn)大數(shù)相乘算法
- 01-10Android 友盟第三方登錄與分享的實(shí)現(xiàn)代
- 01-10android實(shí)現(xiàn)指紋識(shí)別功能
- 01-10如何給Flutter界面切換實(shí)現(xiàn)點(diǎn)特效
- 01-10Android實(shí)現(xiàn)圓形漸變加載進(jìn)度條
- 01-10Emoji表情在Android JNI中的兼容性問題詳
隨機(jī)閱讀
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10delphi制作wav文件的方法
- 04-02jquery與jsp,用jquery
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05織夢dedecms什么時(shí)候用欄目交叉功能?
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子