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图文弹幕源码

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值