Last active
August 13, 2016 06:51
-
-
Save panthole/ce11aead4f0b88c753bef3f62e7c8cf5 to your computer and use it in GitHub Desktop.
弹幕异步图片下载
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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