您的位置:首页 > 移动开发 > 微信开发

Android弹幕实现:基于B站弹幕开源系统(7)QQ、微信聊天气泡样式的弹幕

2017-06-08 16:46 656 查看
Android弹幕实现:基于B站弹幕开源系统(7)QQ、微信聊天气泡样式的弹幕

在附录文章得基础上,改进普通文本弹幕,实现一种特殊效果的文本弹幕,像QQ、微信一样的带有气泡背景的弹幕。实现的重点是在SpannedCacheStuffer。同时要准备若干需要衬在文本弹幕背景部分的.9.png图片。

上层Java代码:
package zhangfei.danmaku;

import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextPaint;
import android.util.Log;
import android.view.View;

import com.github.lzyzsd.randomcolor.RandomColor;

import java.util.HashMap;

import master.flame.danmaku.controller.IDanmakuView;
import master.flame.danmaku.danmaku.model.BaseDanmaku;
import master.flame.danmaku.danmaku.model.DanmakuTimer;
import master.flame.danmaku.danmaku.model.IDanmakus;
import master.flame.danmaku.danmaku.model.IDisplayer;
import master.flame.danmaku.danmaku.model.android.DanmakuContext;
import master.flame.danmaku.danmaku.model.android.SpannedCacheStuffer;
import master.flame.danmaku.ui.widget.DanmakuView;

public class MainActivity extends AppCompatActivity {
private DanmakuView mDanmakuView;
private DanmakuContext mContext;
private AcFunDanmakuParser mParser;

private AppCompatActivity mActivity;

private final String TAG = getClass().getSimpleName();

private BackgroundCacheStuffer mBackgroundCacheStuffer = new BackgroundCacheStuffer();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivity = this;
setContentView(R.layout.activity_main);

mContext = DanmakuContext.create();
mParser = new AcFunDanmakuParser();

initDanmakuView();

findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
addItems();
}
});
}

private void initDanmakuView() {
// 设置最大显示行数
HashMap<Integer, Integer> maxLinesPair = new HashMap<>();
maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL, 5); // 滚动弹幕最大显示5行
// 设置是否禁止重叠
HashMap<Integer, Boolean> overlappingEnablePair = new HashMap<Integer, Boolean>();
overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_RL, true);
overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_TOP, true);

mDanmakuView = (DanmakuView) findViewById(R.id.sv_danmaku);

mContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN, 10)
.setDuplicateMergingEnabled(false)
.setScrollSpeedFactor(1.2f)
.setScaleTextSize(1.0f)
.setCacheStuffer(mBackgroundCacheStuffer, null)
// 绘制背景使用BackgroundCacheStuffer
.setMaximumLines(maxLinesPair)
.preventOverlapping(overlappingEnablePair).setDanmakuMargin(40);

if (mDanmakuView != null) {
mDanmakuView.setCallback(new master.flame.danmaku.controller.DrawHandler.Callback() {
@Override
public void updateTimer(DanmakuTimer timer) {
}

@Override
public void drawingFinished() {

}

@Override
public void danmakuShown(BaseDanmaku danmaku) {

}

@Override
public void prepared() {
mDanmakuView.start();
}
});

mDanmakuView.setOnDanmakuClickListener(new IDanmakuView.OnDanmakuClickListener() {

@Override
public boolean onDanmakuClick(IDanmakus danmakus) {
BaseDanmaku latest = danmakus.last();
if (null != latest) {
return true;
}
return false;
}

@Override
public boolean onDanmakuLongClick(IDanmakus danmakus) {
return false;
}

@Override
public boolean onViewClick(IDanmakuView view) {
return false;
}
});

mDanmakuView.prepare(mParser, mContext);
// mDanmakuView.showFPS(true);
mDanmakuView.enableDanmakuDrawingCache(true);
}
}

private void addItems() {
RandomColor randomColor = new RandomColor();

int id = (int) (Math.random() * 10) % 3;

int resId;
switch (id) {
case 0:
resId = R.drawable.bg_01;
break;

case 1:
resId = R.drawable.bg_02;
break;

case 2:
resId = R.drawable.bg_03;
break;

default:
resId = R.drawable.bg_01;
break;
}

String s = "";
int count = (int) (Math.random() * 100) % 10 + 1;
for (int i = 0; i < count; i++) {
s = s + i;
}

addDanmaKuTextWithBackgroundImage(resId, s, randomColor.randomColor(), false);
}

/**
* 绘制背景(自定义弹幕样式)
*/
private class BackgroundCacheStuffer extends SpannedCacheStuffer {
@Override
public void measure(BaseDanmaku danmaku, TextPaint paint, boolean fromWorkerThread) {
danmaku.padding = 50; // 在背景绘制模式下增加padding
super.measure(danmaku, paint, fromWorkerThread);
}

@Override
public void drawBackground(BaseDanmaku danmaku, Canvas canvas, float left, float top) {
Object object = danmaku.tag;
if (object instanceof DanmakuTag) {
DanmakuTag danmakuTag = (DanmakuTag) object;

Drawable drawable = ContextCompat.getDrawable(mActivity, danmakuTag.bitmapResId);

float height = danmaku.paintHeight;
float width = danmaku.paintWidth;

Rect rect = new Rect(0, 0, (int) width, (int) height);
drawable.setBounds(rect);
drawable.draw(canvas);
}
}

@Override
public void drawStroke(BaseDanmaku danmaku, String lineText, Canvas canvas, float left,
float top, Paint paint) {
// 禁用描边绘制
}
}

private void addDanmaKuTextWithBackgroundImage(int bitmap_resId, String msg,
int textColor, boolean islive) {
BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
if (danmaku == null) {
Log.e(TAG, "BaseDanmaku空");
}

DanmakuTag danmakuTag = new DanmakuTag();
danmakuTag.bitmapResId = bitmap_resId;

danmaku.setTag(danmakuTag);

danmaku.text = "    " + msg + "      ";
// danmaku.padding = 5;
danmaku.priority = 1; // 一定会显示, 一般用于本机发送的弹幕
danmaku.isLive = islive;
danmaku.setTime(mDanmakuView.getCurrentTime() + 1200);
danmaku.textSize = 25f * (mParser.getDisplayer().getDensity() - 0.6f);
danmaku.textColor = textColor;
danmaku.textShadowColor = 0; // 重要:如果有图文混排,最好不要设置描边(设textShadowColor=0),否则会进行两次复杂的绘制导致运行效率降低
// danmaku.underlineColor = Color.GREEN;
// danmaku.borderColor=new RandomColor().randomColor();

mDanmakuView.addDanmaku(danmaku);
}

private class DanmakuTag {
public int bitmapResId;
}

@Override
protected void onPause() {
super.onPause();
if (mDanmakuView != null && mDanmakuView.isPrepared()) {
mDanmakuView.pause();
}
}

@Override
protected void onResume() {
super.onResume();
if (mDanmakuView != null && mDanmakuView.isPrepared() && mDanmakuView.isPaused()) {
mDanmakuView.resume();
}
}

@Override
protected void onDestroy() {
super.onDestroy();
if (mDanmakuView != null) {
// dont forget release!
mDanmakuView.release();
mDanmakuView = null;
}
}

@Override
public void onBackPressed() {
super.onBackPressed();
if (mDanmakuView != null) {
// dont forget release!
mDanmakuView.release();
mDanmakuView = null;
}
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
mDanmakuView.getConfig().setDanmakuMargin(20);
} else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
mDanmakuView.getConfig().setDanmakuMargin(40);
}
}
}


代码运行结果:



附录:
1,《Android弹幕实现:基于B站弹幕开源系统(1)》链接:http://blog.csdn.net/zhangphil/article/details/68067100   
2,《Android弹幕实现:基于B站弹幕开源系统(2)》链接:http://blog.csdn.net/zhangphil/article/details/68114226   
3,《Android弹幕实现:基于B站弹幕开源系统(3)-文本弹幕的完善和细节调整》链接:http://blog.csdn.net/zhangphil/article/details/68485505  
4,《Android弹幕实现:基于B站弹幕开源系统(4)-重构》链接:http://blog.csdn.net/zhangphil/article/details/68947236  
5,《Android弹幕实现:基于B站弹幕开源系统(5)-抽象和复用》链接:http://blog.csdn.net/zhangphil/article/details/69400428 
6,《Android弹幕实现:基于B站弹幕开源系统(6)带用户头像且头像从网络加载》链接:http://blog.csdn.net/zhangphil/article/details/72778984  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐