Skip to content

Instantly share code, notes, and snippets.

@panthole
Last active August 13, 2016 06:51
Show Gist options
  • Save panthole/ce11aead4f0b88c753bef3f62e7c8cf5 to your computer and use it in GitHub Desktop.
Save panthole/ce11aead4f0b88c753bef3f62e7c8cf5 to your computer and use it in GitHub Desktop.
弹幕异步图片下载
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.view.View;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import master.flame.danmaku.controller.DrawHandler;
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.IDisplayer;
import master.flame.danmaku.danmaku.model.android.BaseCacheStuffer;
import master.flame.danmaku.danmaku.model.android.DanmakuContext;
import master.flame.danmaku.danmaku.model.android.Danmakus;
import master.flame.danmaku.danmaku.model.android.SpannedCacheStuffer;
import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
/**
* Created by panlingyue on 3/16/16.
*/
public class RarrangeControl {
private static final String TAG = "RarrangeControl";
//透明黑色 背景
private static final int BLACK_COLOR = 0x99000000;
//滚屏速度,越大速度越慢
private static final float SPEED_FACTOR = 2.0f;
//最大显示行数
private static final int MAX_NUM_LINE = 3;
private static IDanmakuView mDanmakuView;
private WeakReference<Context> weakReference;
private DanmakuContext mDanmakuContext;
private BaseDanmakuParser mParser;
private int DANMU_PADDING_INNER = 3;
private int DANMU_TOP_PADDING_INNER = 17;
private int DANMU_BOTTOM_PADDING_INNER = 2;
private int DANMU_LEFT_PADDING_INNER = 4;
//圆角半径
private int DANMU_RADIUS = 60;
private int DANMU_STOKE = 2;
private int DANMU_BACKGROUND = 1;
//图片显示大小
private int IMAGE_SIZE = 36;
//图片显示大小
private int IMAGE_SIZE_HEIGTH = 40;
//描边宽度
private int STOKE_WIDTH = 1;
//背景边距
private int DANMU_PADDING = 4;
private HashMap<Integer, Bitmap> bitmaps = new HashMap<Integer, Bitmap>();
private ChatMessageSpeak msg;
private View view;
private BaseCacheStuffer.Proxy mCacheStufferAdapter = new BaseCacheStuffer.Proxy() {
@Override public void prepareDrawing(final BaseDanmaku danmaku, boolean fromWorkerThread) {
}
@Override public void releaseResource(BaseDanmaku danmaku) {
if (danmaku.text instanceof Spanned) {
danmaku.text = "";
}
}
};
public RarrangeControl(Context context) {
this.weakReference = new WeakReference<>(context);
setSize(context);
initRarrange();
}
private void setSize(Context context) {
DANMU_PADDING_INNER = Device.dip2px(context, DANMU_PADDING_INNER);
DANMU_TOP_PADDING_INNER = Device.dip2px(context, DANMU_TOP_PADDING_INNER);
DANMU_BOTTOM_PADDING_INNER = Device.dip2px(context, DANMU_BOTTOM_PADDING_INNER);
DANMU_LEFT_PADDING_INNER = Device.dip2px(context, DANMU_LEFT_PADDING_INNER);
DANMU_RADIUS = Device.dip2px(context, DANMU_RADIUS);
DANMU_STOKE = Device.dip2px(context, DANMU_STOKE);
DANMU_BACKGROUND = Device.dip2px(context, DANMU_BACKGROUND);
IMAGE_SIZE = Device.dip2px(context, IMAGE_SIZE);
IMAGE_SIZE_HEIGTH = Device.dip2px(context, IMAGE_SIZE_HEIGTH);
STOKE_WIDTH = Device.dip2px(context, STOKE_WIDTH);
DANMU_PADDING = Device.dip2px(context, DANMU_PADDING);
}
/**
* 初始化弹幕
*/
private void initRarrange() {
// 设置最大显示行数
HashMap<Integer, Integer> maxLinesPair = new HashMap<Integer, Integer>();
maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL, MAX_NUM_LINE);
// 设置是否禁止重叠
HashMap<Integer, Boolean> overlappingEnablePair = new HashMap<Integer, Boolean>();
overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_RL, true);
overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_TOP, true);
mDanmakuContext = DanmakuContext.create();
mDanmakuContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN, STOKE_WIDTH)
.setDuplicateMergingEnabled(false)
.setScrollSpeedFactor(SPEED_FACTOR)
.setScaleTextSize(1.2f)
.setCacheStuffer(new BackgroundCacheStuffer(),
mCacheStufferAdapter) // 绘制背景使用BackgroundCacheStuffer
.setMaximumLines(maxLinesPair)
.preventOverlapping(overlappingEnablePair);
}
public void setDanmakuView(IDanmakuView mDanmakuView) {
this.mDanmakuView = mDanmakuView;
initDanmuView();
}
private void initDanmuView() {
if (mDanmakuView != null) {
mDanmakuView.setCallback(new DrawHandler.Callback() {
@Override public void prepared() {
mDanmakuView.start();
}
@Override public void updateTimer(DanmakuTimer timer) {
}
@Override public void danmakuShown(BaseDanmaku danmaku) {
}
@Override public void drawingFinished() {
}
});
}
mParser = new BaseDanmakuParser() {
@Override protected Danmakus parse() {
return new Danmakus();
}
};
mDanmakuView.prepare(mParser, mDanmakuContext);
mDanmakuView.enableDanmakuDrawingCache(true);
}
public void pause() {
if (mDanmakuView != null && mDanmakuView.isPrepared()) {
mDanmakuView.pause();
}
}
public void hide() {
if (mDanmakuView != null) {
mDanmakuView.hide();
}
}
public void show() {
if (mDanmakuView != null) {
mDanmakuView.show();
}
}
public void resume() {
if (mDanmakuView != null && mDanmakuView.isPrepared() && mDanmakuView.isPaused()) {
mDanmakuView.resume();
}
}
public void destroy() {
if (mDanmakuView != null) {
mDanmakuView.release();
mDanmakuView = null;
}
}
public void addDanmaImage(ChatMessageSpeak msg, View view) {
this.msg = msg;
this.view = view;
//创建链接
HashMap<Integer, String> urls = createUrls(msg.opUserInfo.userIcon,
StringUtils.stringAppend(Constants.QIXIU_NOBEL_X, msg.opUserInfo.badgeLevel));
//创建默认图
HashMap<Integer, Integer> defaultPics = createPics(R.drawable.person_avator_default, 0);
//通过链接地址获取所有图片,并用bitmaps返回结果
createDanmaKu(weakReference.get(), urls, defaultPics, bitmaps);
}
private HashMap<Integer, String> createUrls(String... urls) {
HashMap<Integer, String> urlMap = new HashMap<Integer, String>();
for (int i = 0; i < urls.length; i++) {
urlMap.put(i, urls[i]);
}
return urlMap;
}
private HashMap<Integer, Integer> createPics(int... pics) {
HashMap<Integer, Integer> urlMap = new HashMap<Integer, Integer>();
for (int i = 0; i < pics.length; i++) {
urlMap.put(i, pics[i]);
}
return urlMap;
}
private void createDanmaKu(Context context, HashMap<Integer, String> urls,
HashMap<Integer, Integer> defaultPics, HashMap<Integer, Bitmap> bitmaps) {
if (context == null || urls.size() <= 0) return;
CyclicBarrier cb = new CyclicBarrier(urls.size(), new ContentTask(bitmaps));
for (int i = 0; i < urls.size(); i++) {
new PicassoImageTask(context, cb, i, urls.get(i), defaultPics.get(i), bitmaps).start();
}
}
private Bitmap convertViewToBitmap(View view) {
view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
return bitmap;
}
public void addDanmaKuShowTextAndImage(ChatMessageSpeak msg, Drawable... drawables) {
BaseDanmaku danmaku = mDanmakuContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
boolean isSelf = false;
String content = "";
int count = 0;
long curTime = 0;
if (msg != null) {
content = " " + msg.opUserInfo.nickName + " " + msg.opInfo.content;
drawables[0].setBounds(0, 0, IMAGE_SIZE, IMAGE_SIZE_HEIGTH);
count++;
if (UserController.isLogin()
&& !StringUtils.isEmpty(UserController.getUserId())
&& !StringUtils.isEmpty(msg.opUserInfo.userId)) {
if (TextUtils.equals(UserController.getUserId(), msg.opUserInfo.userId)) {
isSelf = true;
}
}
if (mDanmakuView != null) {
curTime = mDanmakuView.getCurrentTime();
}
SpannableStringBuilder text =
createSpannable(drawables[0], content, msg.opUserInfo.nickName.length());
if (null == text) {
danmaku.text = "";
} else {
danmaku.text = text;
}
danmaku.content = content;
danmaku.count = count;
danmaku.padding = 5;
danmaku.priority = 0;
danmaku.self = isSelf;
danmaku.isLive = true;
danmaku.time = curTime + 500;
danmaku.textSize = 12f * mParser.getDisplayer().getDensity();
danmaku.textColor = Color.WHITE;
danmaku.textShadowColor = Color.BLACK;
if (mDanmakuView != null && danmaku != null) {
mDanmakuView.addDanmaku(danmaku);
}
}
}
private SpannableStringBuilder createSpannable(Drawable mDrawable, String text, int length) {
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
if (mDrawable != null) {
spannableStringBuilder.append(text);
CenteredImageSpan span = new CenteredImageSpan(mDrawable, weakReference.get());
spannableStringBuilder.setSpan(span, 0, text.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
spannableStringBuilder.append(text);
spannableStringBuilder.setSpan(new ForegroundColorSpan(
weakReference.get().getResources().getColor(R.color.liveroom_barrange_nickname)),
text.length(), text.length() + length + 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
} else {
spannableStringBuilder.append(text);
spannableStringBuilder.setSpan(new ForegroundColorSpan(
weakReference.get().getResources().getColor(R.color.liveroom_barrange_nickname)), 0,
length + 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return spannableStringBuilder;
}
/**
* 绘制背景(自定义弹幕样式)
*/
private class BackgroundCacheStuffer extends SpannedCacheStuffer {
final Paint paint = new Paint();
@Override public void measure(BaseDanmaku danmaku, TextPaint paint, boolean fromWorkerThread) {
danmaku.padding = DANMU_PADDING;
super.measure(danmaku, paint, fromWorkerThread);
}
@Override
public void drawBackground(BaseDanmaku danmaku, Canvas canvas, float left, float top) {
paint.setColor(BLACK_COLOR);
paint.setAntiAlias(true);
canvas.drawRoundRect(new RectF(left + DANMU_LEFT_PADDING_INNER, top + DANMU_TOP_PADDING_INNER,
left + danmaku.paintWidth, top + danmaku.paintHeight - DANMU_BOTTOM_PADDING_INNER),
DANMU_RADIUS, DANMU_RADIUS, paint);
}
@Override
public void drawStroke(BaseDanmaku danmaku, String lineText, Canvas canvas, float left,
float top, Paint paint) {
//super.drawStroke(danmaku, lineText, canvas, left, top, paint);
//paint.setStyle(Paint.Style.STROKE);
//paint.setColor(danmaku.textShadowColor);
//paint.setStrokeWidth(STOKE_WIDTH);
//canvas.drawText(danmaku.content, left + danmaku.count * IMAGE_SIZE, top + DANMU_STOKE, paint);
}
}
/**
* 开启子线程下载图片
*/
private class PicassoImageTask extends Thread {
private Context context;
private CyclicBarrier cb;
private int index;
private String url;
private int defaultPic;
private HashMap<Integer, Bitmap> bitmaps;
public PicassoImageTask(Context context, CyclicBarrier cb, int index, String url,
int defaultPic, HashMap<Integer, Bitmap> bitmaps) {
this.context = context;
this.cb = cb;
this.index = index;
this.url = url;
this.bitmaps = bitmaps;
this.defaultPic = defaultPic;
}
public void run() {
AndroidUtilities.runOnUIThread(new Runnable() {
@Override public void run() {
Picasso.with(context).load(url).into(new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
bitmaps.put(index, bitmap);
try {
cb.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {
if (defaultPic != 0) {
bitmaps.put(index, BitmapFactory.decodeResource(context.getResources(), defaultPic));
}else{
bitmaps.put(index, null);
}
try {
cb.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable){
}
});
}
});
}
}
/**
* 将下载的图片绘制成即将发送的弹幕
*/
private class ContentTask implements Runnable {
private HashMap<Integer, Bitmap> bitmaps;
public ContentTask(HashMap<Integer, Bitmap> bitmaps) {
this.bitmaps = bitmaps;
}
public void run() {
AndroidUtilities.runOnUIThread(new Runnable() {
@Override public void run() {
ImageCircleView mImageCircleView = (ImageCircleView) view.findViewById(R.id.user_icon);
ImageView mImageView = (ImageView) view.findViewById(R.id.user_level_crown);
if (bitmaps.get(0) != null && bitmaps.get(1) != null) {
mImageCircleView.setImageBitmap(bitmaps.get(0));
mImageView.setImageBitmap(bitmaps.get(1));
Drawable mDrawable =
new BitmapDrawable(weakReference.get().getResources(), convertViewToBitmap(view));
addDanmaKuShowTextAndImage(msg, mDrawable);
}
}
});
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment