Android弹幕实现:基于B站弹幕开源系统(6)带用户头像且头像从网络加载
Android弹幕实现:基于B站弹幕开源系统(6)带用户头像且头像从网络加载
在附录文章1,2,3,4,5基础上,实现一种特殊弹幕效果,实现弹幕带发表者头像。这种需求在一些开发场景中比较有用,比如在一些视频中,不同等级的用户显示不同的头像,或者本身发出来的弹幕就要求头像。
代码:
package zhangfei.danmaku; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.v4.graphics.drawable.RoundedBitmapDrawable; import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.style.BackgroundColorSpan; import android.text.style.ImageSpan; import android.util.Log; import android.view.View; import java.util.HashMap; import java.util.concurrent.Callable; import io.reactivex.Observable; import io.reactivex.ObservableSource; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.observers.DisposableObserver; import io.reactivex.schedulers.Schedulers; 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.BaseCacheStuffer; import master.flame.danmaku.danmaku.model.android.DanmakuContext; import master.flame.danmaku.danmaku.model.android.SpannedCacheStuffer; import master.flame.danmaku.ui.widget.DanmakuView; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class MainActivity extends AppCompatActivity { private DanmakuView mDanmakuView; private DanmakuContext mContext; private AcFunDanmakuParser mParser; private final String TAG = getClass().getSimpleName(); private OkHttpClient mOkHttpClient; private CompositeDisposable mCompositeDisposable = new CompositeDisposable(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mOkHttpClient = new OkHttpClient(); mContext = DanmakuContext.create(); mParser = new AcFunDanmakuParser(); initDanmakuView(); final String url="http://avatar.csdn.net/9/7/A/1_zhangphil.jpg"; findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { addItems(url); } }); } 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, 3) .setDuplicateMergingEnabled(false).setScrollSpeedFactor(1.2f).setScaleTextSize(1.2f) .setCacheStuffer(new SpannedCacheStuffer(), mCacheStufferAdapter) // 图文混排使用SpannedCacheStuffer // .setCacheStuffer(new BackgroundCacheStuffer()) // // 绘制背景使用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 BaseCacheStuffer.Proxy mCacheStufferAdapter = new BaseCacheStuffer.Proxy() { @Override public void prepareDrawing(final BaseDanmaku danmaku, boolean fromWorkerThread) { } @Override public void releaseResource(BaseDanmaku danmaku) { // TODO 重要:清理含有ImageSpan的text中的一些占用内存的资源 例如drawable } }; private void addItems(final String url) { DisposableObserver disposableObserver = new DisposableObserver<Bitmap>() { @Override public void onNext(@NonNull Bitmap bmp) { addDanmaKuShowTextAndImage(bmp, "zhang phil @ csdn", Color.DKGRAY, Color.RED, false); } @Override public void onComplete() { } @Override public void onError(Throwable e) { Log.e(TAG, e.toString(), e); } }; mCompositeDisposable.add( getBitmapObservable(url) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribeWith(disposableObserver) ); } private Observable<Bitmap> getBitmapObservable(@NonNull final String url) { return Observable.defer(new Callable<ObservableSource<Bitmap>>() { @Override public ObservableSource<Bitmap> call() throws Exception { Bitmap bmp = null; //同步方法返回观察者需要的数据结果 //在这里处理线程化的操作 Request request = new Request.Builder().url(url).build(); Response response = mOkHttpClient.newCall(request).execute(); try { if (response.isSuccessful()) { byte[] bytes = response.body().bytes(); bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); } } catch (Exception e) { e.printStackTrace(); } return Observable.just(bmp); } }); } private void addDanmaKuShowTextAndImage(Bitmap bitmap, String msg, int textColor, int bgColor, boolean islive) { BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL); if (danmaku == null) { Log.e(TAG, "BaseDanmaku空"); } //最里面的图像 RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(getResources(), bitmap); drawable.setCircular(true); drawable.setAntiAlias(true); drawable.setCornerRadius(Math.max(bitmap.getWidth(), bitmap.getHeight())); drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight()); SpannableStringBuilder spannable = createSpannable(drawable, msg, bgColor); danmaku.text = spannable; 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; mDanmakuView.addDanmaku(danmaku); } private SpannableStringBuilder createSpannable(Drawable drawable, String msg, int color) { String text = "image"; SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(text); spannableStringBuilder.append(msg); ImageSpan span = new ImageSpan(drawable);// ImageSpan.ALIGN_BOTTOM); spannableStringBuilder.setSpan(span, 0, text.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spannableStringBuilder.setSpan(new BackgroundColorSpan(color), 0, spannableStringBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return spannableStringBuilder; } @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; } //取消所有Okhttp的网络请求 mOkHttpClient.dispatcher().cancelAll(); mCompositeDisposable.clear(); } @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/65936066
5,《Android弹幕实现:基于B站弹幕开源系统(5)-抽象和复用》链接:http://blog.csdn.net/zhangphil/article/details/69400428
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
使用函数计算来抽取apk信息
在之前的博客中我们看到,可以使用函数计算来实现一个自定义的图像处理服务,这个服务是稳定、可靠、弹性伸缩的,并且它是无服务器架构,按函数的调用时间收费,节省了服务器闲置的开销和运维成本。 使用函数计算可以方便地构建类似的微服务,比如我们可以创建一个处理android apk文件的微服务: 小吴将下载的apk文件上传到OSS 他想分析一下这些apk应用的权限信息: 使用aapt工具抽取出每个apk文件的权限信息 将它们录入到数据库中(rds),方便日后查询 步骤 1. 创建一个OSS bucket https://oss.console.aliyun.com/index#/ 注意创建bucket时选择“华东2”区域。 2. 创建RDS数据库 https://rdsnew.console.aliyun.com/ 在RDS控制台创建一个实例(注意选择华东2区域和
- 下一篇
C#判断访问网站的设备类型
同样也是在破解版的HISHOP源码上扒出来的,代码如下: protected void InitVisitorTerminal() { VisitorTerminal visitorTerminal = new VisitorTerminal(); string userAgent = base.Request.UserAgent; if (string.IsNullOrWhiteSpace(userAgent)) { userAgent = ""; } userAgent = userAgent.ToLower(); bool flag = userAgent.Contains("ipad"); bool flag1 = userAgent.Contains("iphone os"); bool flag2 = userAgent.Contains("midp"); bool flag3 = userAgent.Contains("rv:1.2.3.4"); flag3 = (flag3 ? flag3 : userAgent.Contains("ucweb")); bool fla...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- SpringBoot2全家桶,快速入门学习开发网站教程