Android 圖文彈幕 不疊加 不丟失

現在直播啊 網紅這麼火、好多互聯網公司打直播的主意、好撈一點投資
有直播那麼肯定離不開彈幕、現在時下最流行的第三方庫是Bilibili
好東西要分享 上網址
https://github.com/Bilibili/DanmakuFlameMaster
http://wangpeiyuan.cn/2016/02/24/%E8%AE%B0%E4%B8%80%E6%AC%A1%E5%BC%B9%E5%B9%95%E7%9A%84%E5%BC%80%E5%8F%91/

但是這種彈幕適合免費全屏刷的那種彈幕、如果是需要圖文修改挺麻煩 需要canvas來畫、這個我也是實現了、有過想了解可以私信我
保證不丟失 不疊加、
此library只滿足兩種、要不就丟失不疊加 要不就不丟失 疊加、那麼我就考慮使用動畫
廢話少說 上動態圖
這裏寫圖片描述

那麼我們先說一下思路、
動畫首先要有動畫通道、那麼通過自定義控件封裝成通道、
通道關鍵是一個屬性一個方法
isRunning;
startAnimation()
isRunning默認是false、在動畫監聽 start設置爲true end設置爲false

寫一個一個danmuManager 管理類
通過mqtt或者是其他即時通訊的方法獲取到彈幕、獲取到彈幕後、
首先將danmuentity存放到Queque(隊列)中
我們可以looperDanmu
循環所有的通道、判斷通道有沒有在執行動畫、有過有一個沒有那麼 調用通道的startAnimation()
然後queue.poll(); 移除這個danmuentity

如果這麼寫的話、是不能保證所有的彈幕都不丟失、因爲如果我們有三個通道、瞬間來了六條彈幕、
那麼循環完畢只會展示三條彈幕、剩下的三條還存放在queue中、那麼我們的觸發點在哪裏呢、
有的人通過timerthread來每個幾秒獲取一個、但是是耗資源的、

那麼我們可以在通道上打主意、如果動畫執行完畢、主動去執行 looperDanmu、如果queue中還有
danmuentity那麼繼續startAnimation。。。 這樣就保證了不丟失不疊加

好了上代碼
定義彈幕動作接口

/**
 * Created by walkingMen on 2016/5/12.
 * 彈幕動作類
 */
public interface DanmakuActionInter {
    /**
     * 添加彈幕
     */
    void addDanmu(DanmakuEntity dan);

    /**
     * 移出彈幕
     */
    void pollDanmu();
}

自定義管道控件

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.media.ExifInterface;
import android.os.Build;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.just.sun.R;
import com.just.sun.widget.danmu.AnimationHelper;
import com.just.sun.widget.danmu.ScreenUtils;

import java.io.IOException;

/**
 * Created by walkingMen on 2016/5/12.
 */
public class DanmakuChannel extends RelativeLayout {

    public boolean isRunning = false;
    public DanmakuEntity mEntity;
    private DanmakuActionInter danAction;

    public DanmakuActionInter getDanAction() {
        return danAction;
    }

    public void setDanAction(DanmakuActionInter danAction) {
        this.danAction = danAction;
    }

    public DanmakuChannel(Context context) {
        super(context);
        init();
    }


    public DanmakuChannel(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public DanmakuChannel(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public DanmakuChannel(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init() {
        LayoutInflater inflater = LayoutInflater.from(getContext());
        inflater.inflate(R.layout.danmaku_channel_layout, null);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            this.setClipToOutline(false);
        }
    }


    public void setDanmakuEntity(DanmakuEntity entity) {
        mEntity = entity;
    }

    public void mStartAnimation(DanmakuEntity entity) {
        isRunning = true;
        setDanmakuEntity(entity);
        if (mEntity != null) {
            final View view = View.inflate(getContext(), R.layout.item_live_danmu, null);
            TextView contentView = (TextView) view.findViewById(R.id.content);
            contentView.setText(entity.text);
            view.measure(-1, -1);
            int measuredWidth = view.getMeasuredWidth();
            int measuredHeight = view.getMeasuredHeight();
            int leftMargin = ScreenUtils.getScreenW(getContext());
            Animation anim = AnimationHelper.createTranslateAnim(getContext(), leftMargin, -measuredWidth);
            anim.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {

                }

                @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
                @Override
                public void onAnimationEnd(Animation animation) {
                    if (!((Activity) getContext()).isDestroyed()) {//防止內存溢出
                        new Handler().post(new Runnable() {
                            public void run() {
                                view.clearAnimation();
                                DanmakuChannel.this.removeView(view);
                                if (danAction != null) {
                                    danAction.pollDanmu();
                                }
                            }
                        });
                    }
                    isRunning = false;
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                }
            });
            view.startAnimation(anim);
            this.addView(view);
        }
    }
}

danmaku_channel_layout 只是一個RelativeLayout、
item_live_danmu 自己定義成所需的樣式
view.measure(-1, -1); 重新繪製、獲取高寬、以便動畫 fromx tox
DanmakuEntity 自己定義即可、

好了 我們繼續創建管理類

package com.just.sun.widget.danmu.DanmuBase;


import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

/**
 * Created by walkingMen on 2016/5/12.
 */
public class DanmakuActionManager implements DanmakuActionInter {
    public List<DanmakuChannel> channels = new LinkedList<>();

    public Queue<DanmakuEntity> danEntities = new LinkedList<>();

    @Override
    public void addDanmu(DanmakuEntity dan) {
        danEntities.add(dan);
        looperDan();
    }

    @Override
    public void pollDanmu() {
        looperDan();
    }

    public void addChannel(DanmakuChannel channel) {
        channels.add(channel);
    }

    public DanmakuActionManager() {

    }

    public void looperDan() {
        for (int i = 0; i < channels.size(); i++) {
            if (!channels.get(i).isRunning && danEntities.size() > 0) {
                DanmakuEntity poll = danEntities.poll();
                channels.get(i).mStartAnimation(poll);
            }
        }
    }
}

對了、彈幕內容背景是shape寫的、但是要求是左邊是直角、右邊是圓角 我們可以用layer-list來做

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
        <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
            <!-- 連框顏色值 -->
            <item>
                <shape android:shape="rectangle">
                    <solid android:color="@color/black_transparent_50"/>
                    <corners android:bottomLeftRadius="0dp" android:bottomRightRadius="3dp" android:topLeftRadius="0dp" android:topRightRadius="3dp"></corners>
                </shape>
            </item>
            <!-- 主體背景顏色值 -->
            <item android:bottom="1dp" android:left="0dp" android:right="1dp" android:top="1dp">
                <shape android:shape="rectangle">
                    <solid android:color="@color/black_transparent_50"/>
                    <corners android:bottomLeftRadius="0dp" android:bottomRightRadius="3dp" android:topLeftRadius="0dp" android:topRightRadius="3dp"></corners>
                </shape>
            </item>
        </layer-list>
    </item>
</selector>

在Activity中添加管道 初始化manager

    <LinearLayout
        android:id="@+id/containerVG"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="60dp"
        android:clipChildren="false"
        android:orientation="vertical">

        <com.dan.walkingmen.danapplication.danmu.DanmuBase.DanmakuChannel
            android:id="@+id/danA"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:layout_marginTop="10dp" />

        <com.dan.walkingmen.danapplication.danmu.DanmuBase.DanmakuChannel
            android:id="@+id/danB"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:layout_marginTop="10dp" />

        <com.dan.walkingmen.danapplication.danmu.DanmuBase.DanmakuChannel
            android:id="@+id/danC"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:layout_marginTop="10dp" />

    </LinearLayout>
        danA = (DanmakuChannel) findViewById(R.id.danA);
        danB = (DanmakuChannel) findViewById(R.id.danB);
        danC = (DanmakuChannel) findViewById(R.id.danC);
        danmakuActionManager = new DanmakuActionManager();
        danA.setDanAction(danmakuActionManager);
        danB.setDanAction(danmakuActionManager);
        danC.setDanAction(danmakuActionManager);
        danmakuActionManager.addChannel(danA);
        danmakuActionManager.addChannel(danB);
        danmakuActionManager.addChannel(danC);

以上就是所有的核心代碼、之後我會把項目共享出來
資源鏈接
http://download.csdn.net/detail/qq_28195645/9518926
android圖文彈幕源碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章