現在直播啊 網紅這麼火、好多互聯網公司打直播的主意、好撈一點投資
有直播那麼肯定離不開彈幕、現在時下最流行的第三方庫是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圖文彈幕源碼