Android雙重SurfaceView實(shí)現(xiàn)彈幕效果
本文實(shí)例為大家分享了Android雙重SurfaceView實(shí)現(xiàn)彈幕效果的具體代碼,供大家參考,具體內(nèi)容如下
頁(yè)面布局
首先是XML的layout布局,這里的總的父布局是一個(gè)FrameLayout用于貼上兩個(gè)SurfaceView,一個(gè)用來播放視頻,一個(gè)用來顯示彈幕
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".DanmuActivity"> <SurfaceView android:id="@+id/sv_text" android:layout_width="match_parent" android:layout_height="400dp"/> <SurfaceView android:id="@+id/sv_media" android:layout_width="match_parent" android:layout_height="400dp"/> /> <EditText android:id="@+id/et_text" android:layout_width="300dp" android:layout_height="wrap_content" android:layout_marginTop="450dp"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="發(fā)送" android:layout_marginTop="500dp" android:onClick="Gogo"/> </FrameLayout>
對(duì)象類
創(chuàng)建一個(gè)對(duì)象類來存放你所發(fā)送的彈幕
public class Danmu { String text;//彈幕內(nèi)容 int x;//x軸 int y;//y軸 public Danmu(String text){ this.text = text; //將y設(shè)置為隨機(jī),彈幕出現(xiàn)的位置也為隨機(jī) this.y = (int) (Math.random()*400); this.x = 0; } }
Activity實(shí)現(xiàn)SurfaceHolder.Callback并重寫其方法
先定義需要的東西,播放視頻我們用Mediaplayer
//視頻播放 private MediaPlayer mediaPlayer; //彈幕Surface與視頻Surface private SurfaceView sv_text, sv_media; //兩個(gè)Surface對(duì)應(yīng)的兩個(gè)holder private SurfaceHolder text_holder, media_holder; EditText editText;//字幕輸入框 List<Danmu> list = new ArrayList<>();//存放
初始化MediaPlayer,要在第一步執(zhí)行否則運(yùn)行會(huì)報(bào)空,這里封裝成了一個(gè)方法,直接在onCreate內(nèi)調(diào)用
private void initPlayer() throws IOException { //先判斷是否創(chuàng)建過,沒創(chuàng)建就創(chuàng)建出來 if (mediaPlayer == null) { mediaPlayer = new MediaPlayer(); } mediaPlayer.reset();//使其恢復(fù)空閑狀態(tài) //播放的資源 mediaPlayer.setDataSource("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"); mediaPlayer.prepare();//準(zhǔn)備 mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) {//準(zhǔn)備完畢了 mediaPlayer.start();//播放 } }); }
初始化控件,同樣封裝為方法,holder用對(duì)應(yīng)的Surface獲取到
private void initView() { sv_text = findViewById(R.id.sv_text); text_holder = sv_text.getHolder(); text_holder.addCallback(this); sv_media = findViewById(R.id.sv_media); media_holder = sv_media.getHolder(); media_holder.addCallback(this); editText = findViewById(R.id.et_text); //設(shè)置透明,將播放彈幕的Surface放到第一位并設(shè)置為背景透明 sv_text.setZOrderOnTop(true); text_holder.setFormat(PixelFormat.TRANSPARENT); }
接下來是Surface.Callback重寫的方法
@Override public void surfaceCreated(SurfaceHolder holder) { //判斷當(dāng)前holder是否是media的那個(gè) if (holder == media_holder) { //設(shè)置要顯示的Surfaceholder mediaPlayer.setDisplay(media_holder); //判斷當(dāng)前holder是否是字幕的那個(gè) } else if (holder == text_holder) { //創(chuàng)建線程執(zhí)行耗時(shí)操作 new Thread() { @Override public void run() { super.run(); //死循環(huán)用來一直更新彈幕的位置 while (true) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } Paint paint = new Paint();//創(chuàng)建畫筆 paint.setStrokeWidth(5);//畫筆粗細(xì) paint.setColor(Color.GREEN);//畫筆顏色 paint.setTextSize(30);//設(shè)置文字大小 //創(chuàng)建畫板 Canvas canvas = text_holder.lockCanvas(); //判斷若畫板為空則跳出循環(huán) if (canvas == null) { break; } //設(shè)置畫布顏色,透明 canvas.drawColor(PixelFormat.TRANSPARENT, PorterDuff.Mode.CLEAR); //用循環(huán)來你的彈幕集合并且在畫板上展示出來 //x+=20為你的彈幕在不斷的從左到右移動(dòng) for (Danmu danmu : list) { canvas.drawText(danmu.text, danmu.x += 20, danmu.y, paint); //若移動(dòng)的位置大于視頻Surface的寬度了就歸0 if (danmu.x > sv_media.getWidth()) { danmu.x = 0; } } //將畫布解鎖并顯示到屏幕上 text_holder.unlockCanvasAndPost(canvas); } } }.start();//不要忘記開啟線程 } }
發(fā)送的按鈕的點(diǎn)擊事件
public void Gogo(View view) { //先判斷輸入框里有沒有東西 if (!editText.getText().toString().isEmpty() && !editText.getText().toString().equals("")) { Danmu danmu = new Danmu(editText.getText().toString()); list.add(danmu); } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android自定義View實(shí)現(xiàn)彈幕效果
- Android實(shí)現(xiàn)視頻彈幕功能
- Android自制精彩彈幕效果
- Android EasyBarrage實(shí)現(xiàn)輕量級(jí)彈幕效果
- Android編程實(shí)現(xiàn)簡(jiǎn)易彈幕效果示例【附demo源碼下載】
- 很棒的Android彈幕效果實(shí)例
- Android 實(shí)現(xiàn)仿網(wǎng)絡(luò)直播彈幕功能詳解及實(shí)例
- Android實(shí)現(xiàn)炫酷的網(wǎng)絡(luò)直播彈幕功能
- Android彈幕框架 黑暗火焰使基本使用方法
- Android仿斗魚直播的彈幕效果
- Android實(shí)現(xiàn)自定義的彈幕效果
- 實(shí)例解析如何在Android應(yīng)用中實(shí)現(xiàn)彈幕動(dòng)畫效果
- Android簡(jiǎn)單實(shí)現(xiàn)彈幕效果
相關(guān)文章
Android之解析JSON數(shù)據(jù)示例(android原生態(tài),F(xiàn)astJson,Gson)
本篇文章主要介紹了Android之解析JSON數(shù)據(jù)示例,主要使用android原生態(tài)代碼解析,F(xiàn)astJson,Gson三種方法,有興趣的可以了解一下。2017-02-02Caused by: android.os.NetworkOnMainThreadException錯(cuò)誤解決辦法
這篇文章主要介紹了Caused by: android.os.NetworkOnMainThreadException錯(cuò)誤解決辦法,本文提供了2種解決方法,需要的朋友可以參考下2014-07-07基于Android XML解析與保存的實(shí)現(xiàn)
本篇文章小編為大家介紹,基于Android XML解析與保存的實(shí)現(xiàn)。需要的朋友參考下2013-04-04詳解LeakCanary分析內(nèi)存泄露如何實(shí)現(xiàn)
這篇文章主要為大家介紹了詳解LeakCanary分析內(nèi)存泄露如何實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12Android編程實(shí)現(xiàn)3D立體旋轉(zhuǎn)效果的實(shí)例代碼
這篇文章主要介紹了Android編程實(shí)現(xiàn)3D立體旋轉(zhuǎn)效果的實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05Android應(yīng)用開發(fā)中RecyclerView組件使用入門教程
這篇文章主要介紹了Android應(yīng)用開發(fā)中RecyclerView組件使用的入門教程,RecyclerView主要針對(duì)安卓5.0以上的material design開發(fā)提供支持,需要的朋友可以參考下2016-02-02Flutter滾動(dòng)組件之ListView使用方法詳解
這篇文章主要為大家詳細(xì)介紹了Flutter滾動(dòng)組件之ListView的使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03Android scrollview如何監(jiān)聽滑動(dòng)狀態(tài)
這篇文章主要介紹了Android scrollview監(jiān)聽滑動(dòng)狀態(tài)的實(shí)例代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12flutter InkWell實(shí)現(xiàn)水波紋點(diǎn)擊效果
這篇文章主要為大家詳細(xì)介紹了flutter InkWell實(shí)現(xiàn)水波紋點(diǎn)擊效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07