andriod 基本的直播彈幕實(shí)現(xiàn) (一)

兩種實(shí)現(xiàn)彈幕功能的方法,其實(shí)原理上的差別不大,

第一個(gè)方法是小巫見打巫,因?yàn)榈诙椒ㄊ俏以趃ithub

上面集成下來的在功能完善方面是完虐第一個(gè)的,第一個(gè)方法可以說只是拿來大概的了解它,

這個(gè)直播彈幕大概是個(gè)什么東西!!

第一個(gè)的實(shí)現(xiàn)過程:

xml文件:

1.


2.



3.


一共三個(gè)。

Activity的實(shí)現(xiàn):

--------------------------------------------------------------------定義控件--------------------------------------------------------------------

/////彈幕部分

private BarrageViewbv;

int count;

private Buttonbtn_send;

-----------------------------------------------------------------設(shè)置監(jiān)聽--------------------------------------------------------------------



--------------------------------------------------設(shè)置彈幕內(nèi)容,并加入BarrageView布局中-------------------------------------

主要實(shí)現(xiàn)的兩個(gè)類:

-----------------------------------------------------------BarrageLine?----------------------------------------------


package net.ossrs.yasea.demo.Activity.View;

import android.content.Context;

import android.os.Handler;

import android.os.Looper;

import android.util.AttributeSet;

import android.view.View;

import android.widget.FrameLayout;

import java.util.concurrent.ConcurrentLinkedQueue;

public class BarrageLine extends FrameLayout

{

private HandlermHandler;

private ConcurrentLinkedQueuemQueue =new ConcurrentLinkedQueue<>();

private int mWidth;

private int PADDING =20;

private int HEIGHT =100;

// /**

// * 統(tǒng)一線程池

// */

// public static Executor mExecutor = Executors.newCachedThreadPool();

? ? public BarrageLine(Context context) {

this(context,null);

}

public BarrageLine(Context context, AttributeSet attrs) {

this(context, attrs,0);

}

public BarrageLine(Context context, AttributeSet attrs,int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

private void init() {

///LOOPER用來抽取隊(duì)列里面的東西

? ? ? ? mHandler =new Handler(Looper.getMainLooper());

}

@Override

? ? protected void onAttachedToWindow() {

super.onAttachedToWindow();

flutter();

}

/**

* 設(shè)置一行的寬高

? ? * @param widthMeasureSpec

? ? * @param heightMeasureSpec

? ? */

? ? @Override

? ? protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

this.mWidth = MeasureSpec.getSize(widthMeasureSpec);

setMeasuredDimension(mWidth,HEIGHT);

}

/**

* 網(wǎng)隊(duì)列里添加彈幕view

? ? * @param view

? ? */

? ? public void addBarrage(View view){

mQueue.offer(view);

}

private class AddBarrageTaskimplements Runnable{

Viewview;

public AddBarrageTask(View view){

this.view = view;

}

@Override

? ? ? ? public void run() {

mQueue.offer(view);

}

}

/**

* 開始執(zhí)行動畫

*/

? ? private void flutter(){

mHandler.post(mFlutterTask);

}

private RunnablemFlutterTask =new Runnable() {

@Override

? ? ? ? public void run() {

addBarrageView();

moveView();

mHandler.postDelayed(this,5);

}

};

/**

* 判斷每一行是否要添加view

*/

? ? private void addBarrageView() {

if (getChildCount() ==0){

addNextView();

return;

}

View lastChild =this.getChildAt(getChildCount()-1);

int lastChildRight = (int) (lastChild.getTranslationX()+(int)lastChild.getTag());

if (lastChildRight+PADDING>=mWidth)

return;

addNextView();

}

/**

* 給每一行添加view

*/

? ? private void addNextView(){

if (mQueue.isEmpty())

return;

View view =mQueue.poll();

view.measure(0,0);

view.setTag(view.getMeasuredWidth());

addView(view);

view.setTranslationX(mWidth);

}

/**

* 通過handler.post執(zhí)行,形成動畫

*/

? ? private void moveView() {

if (this.getChildCount()==0)

return;

for (int i=0;i

View view =this.getChildAt(i);

view.setTranslationX(view.getTranslationX()-3);

if (view.getTranslationX()+(int)view.getTag()<=0)

removeBarrageView(view);

}

}

/**

* 當(dāng)view移出彈幕行,刪除

? ? * @param view

? ? */

? ? private void removeBarrageView(View view){

view.setVisibility(GONE);

this.removeView(view);

view =null;

}

/**

* 停止發(fā)消息,取消動畫

*/

? ? private void stop(){

if (mHandler!=null)

mHandler.removeCallbacks(mFlutterTask);

}

@Override

? ? protected void onDetachedFromWindow() {

super.onDetachedFromWindow();

stop();

}

}

-----------------------------------------------------------BarrageView?----------------------------------------------

package net.ossrs.yasea.demo.Activity.View;

import android.content.Context;

import android.util.AttributeSet;

import android.view.View;

import android.view.ViewGroup;

import android.widget.LinearLayout;

import java.util.ArrayList;

import java.util.Random;

public class BarrageView extends LinearLayout

{

private ArrayListmBarrages =new ArrayList();

private RandommRandom;

public BarrageView(Context context) {

this(context,null);

}

public BarrageView(Context context, AttributeSet attrs) {

this(context, attrs,0);

}

public BarrageView(Context context, AttributeSet attrs,int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

/**

* 總共三行彈幕

*/

? ? private void init() {

mRandom =new Random();

setOrientation(LinearLayout.VERTICAL);

for (int i =0; i <3; i++) {

BarrageLine bl =new BarrageLine(getContext());

LinearLayout.LayoutParams param =new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);

bl.setLayoutParams(param);

this.addView(bl);

mBarrages.add(bl);

}

}

/**

* 隨機(jī)添加彈幕到某一行

? ? * @param view

? ? */

? ? public void addBarrage(View view) {

mBarrages.get(mRandom.nextInt(3)).addBarrage(view);

}

/**

* 指定添加彈幕到某一行

? ? * @param view

? ? * @param line

? ? */

? ? public void addBarrage(View view,int line){

mBarrages.get(line).addBarrage(view);

}

}

第一個(gè)實(shí)現(xiàn)的大致原理:

先認(rèn)識到這個(gè)方法的奇葩的地方:就是Textview轉(zhuǎn)view那部分,如果他的布局不是用TextView開始的話,那么就會報(bào)錯

Imageview哪里也是一樣的,這個(gè)涉及到View的加載機(jī)制了!有興趣的可以去了解一下,不過可以確定一點(diǎn),就是xml文件的屬性

是通過加載是的第一個(gè)確定的(如果沒想起了解的想法的,可以先這樣認(rèn)為)。

然后這里要將幾個(gè)閱讀別人源碼是的一些小技巧:

開始時(shí)的第一個(gè)眼神該放在它是否繼承了什么還是說他就是一個(gè)簡單的工具類。




比如這個(gè),繼承的是LinearLayout,說明它是在這個(gè)的基礎(chǔ)上打造的,就會擁有它父類的特性

然后,就需要你去看他是如何調(diào)用的了,特別是在看一個(gè)裝了很多功能的模塊的時(shí)候,

因?yàn)槟闶菫榱四稠?xiàng)需求而去看的,為了實(shí)現(xiàn)才去了解,所以你甚至不需要完全的了解它(如果你的時(shí)間真的說可以的話,

那也不是不可以)。




很明顯,我們的起點(diǎn)可以從這里出發(fā)。然后順著它,我們來到了這里


這里我們可以看出addBarrage這個(gè)方法來自mBarrages,而且這個(gè)mBarrages有g(shù)et這個(gè)方法的,說明它可能是個(gè)list集合。

這是就可以得出一個(gè)初步的想法,傳過來的view被mBarrages.addBarrage調(diào)用(而且還是被這個(gè)集合里面的隨機(jī)其中一個(gè)調(diào)用的)。



然后,我們在看看BarrageView,我們的界面控件。因?yàn)槭荁arrageView實(shí)例化后調(diào)用的addgarrage,所以,我們也需要了解


主要看這一行,如果是其他的話,估計(jì)需要找一下(或者全部知道它),因?yàn)檫@里就只有這一行是信息量最大的,如果你提前看了他是繼承什么的,那這個(gè)看起來一

點(diǎn)都不難理解,不過讀的時(shí)候就有點(diǎn)麻煩,因?yàn)槿绻前催@個(gè)步驟來讀,對于BarrageLine的信息是零,所以我們需要去了解一下BarrageLine

最好帶著疑問去,比如:結(jié)合前面的mBarrages.addBarrage方法,所以我們點(diǎn)進(jìn)去后就可以重點(diǎn)關(guān)注這個(gè)方法究竟是咋樣的,這是我們來到了

這里


mQueue.offer(view);很明顯這是個(gè)加入隊(duì)列的方法,這里也解釋了這一點(diǎn)


到這時(shí),我們有需要了解一下BarrageLine是如何工作的了,因?yàn)樗趯?shí)例化之后加入了我們的BarrageView,所以需要了解它。

如果說要哪里入手的話就有點(diǎn)難講了,畢竟我們從上一個(gè)類哪里得到的信息是,那個(gè)集合里面的它取到了一個(gè)view,

而且被循環(huán)了三次之后被加入了

BarrageView,而且,從他的對齊方式可以大致的想到。。。他應(yīng)該是這樣的


接下來可以說方向就是理解這個(gè)view ,他傳進(jìn)去后是如何是BarrageLine起作用的


?


這里指的了解一下的是Looper是負(fù)責(zé)抽取隊(duì)列里面的東西的


?

?

很明顯這里是判斷是否需要addNextView();的


而這個(gè)就已經(jīng)體現(xiàn)了我們view的作用了,他從隊(duì)列里取了出來,這時(shí)view便可以顯示出來了(如果你問它怎么就顯示出來了,其實(shí)是因?yàn)?/b>

addview這個(gè)方法,F(xiàn)ragmentLayout屬于ViewGroup的布局,這就是為什么在所有開始之前先看他究竟繼承了什么。所以他可以調(diào)用

viewgroup方法),其他部分的無非是銷毀view,停止啊,在個(gè)個(gè)周期之內(nèi)需要怎么做的處理。

總結(jié):其實(shí)第一個(gè)方法貫穿這個(gè)功能實(shí)現(xiàn)的整個(gè)過程的就是那個(gè)view,一步一步的順著線索往下找,就可以找到最終它無非是通過BarrageLine

的方法加入隊(duì)列之后被addBarrageView()--》addNextView()取出,然后隨即的出現(xiàn)在三行BarrageView里面的BarrageLine里面而已。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,853評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,695評論 19 139
  • scheduler定時(shí)調(diào)度系統(tǒng)是大多行業(yè)項(xiàng)目都需要的,傳統(tǒng)的spring-job模式,個(gè)人感覺已經(jīng)out了,因?yàn)榇?..
    安琪拉_4b7e閱讀 2,979評論 4 6
  • 版權(quán)聲明:本文為Yiwent原創(chuàng)文章,轉(zhuǎn)載必須注明出處。 1.登陸界面 對于一個(gè)網(wǎng)絡(luò)APP來說,剛開始首先必須登錄...
    文采逸逸閱讀 1,609評論 6 13
  • 7618買了很多東西 她簡直開心的不得了 梔子花開了~ 很香,超級香,超級喜歡 我得督促我寶寶天天給它澆水,長的棒棒噠
    Ermao閱讀 276評論 1 1

友情鏈接更多精彩內(nèi)容