现在直播啊 网红这么火、好多互联网公司打直播的主意、好捞一点投资
有直播那么肯定离不开弹幕、现在时下最流行的第三方库是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.youkuaiyun.com/detail/qq_28195645/9518926
android图文弹幕源码