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

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
[多图] GitHub 程序语言流行趋势
RedMonk分析师 Donnie Berkholz分析了开源项目托管平台GitHub上的编程语言流行趋势(如图),并对上述语言的趋势进行了解释:Ruby的下降和Java、PHP和Python等的同时上升显示了GitHub走向了主流, 更多的语言社区拥抱了GitHub,更多来自Java、 C++、C#、Obj-C和Shell的开发者加入了GitHub;JavaScript的崛起反应了JavaScript开发框架的流行和 JavaScript鼓励共享复用代码的开发哲学;Windows和iOS的开发语言几乎没有任何变化显示,C#和Objective-C两大生态系统不 鼓励或积极的阻止开源代码。 文章转载自 开源中国社区 [http://www.oschina.net]
- 下一篇
xamarin android 布局尺寸了解
为了使UI界面在不同大小的移动端显示器上能够正常显示,大家可能都知道使用sp作为字体大小的单位,dp作为其他元素长度的单位。 前几天看了一篇文章关于 App设计规范的,文章用心写的非常好,这里是链接http://www.25xt.com/appdesign/10821.html 。但是费解的是所有的长度单位都是用px。好吧,“”原谅“这位UI设计师良心ps的一张app设计规范图。在UI布局的时候有必要了解一下android设备的适应了。 先来问大家几个问题, 1.android设备中有哪些 度量单位? 2.像素的最小单位是多少? 3.什么是屏幕分辨率? 4.什么是独立像素密度? 5.屏幕尺寸是指长和宽的物理尺寸? 说实在了,刚开始这几个问题我知道的也很模糊,也就知道个大概的样子。看了这篇文章你就明白了 1.屏幕尺寸 Screen size屏幕尺寸是表示手机的实际物理尺寸,并不是说设备的长和宽,而是对角线的长度,单位是英寸,1in=2.54cm.市场上常见的屏幕尺寸有3.5、3.7、4.2、5.0、5.5、6.0 2.屏幕分辨率 虽然这个问题太基础了,的确。市场上主流分辨率有480*80...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS8编译安装MySQL8.0.19
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Mario游戏-低调大师作品
- Hadoop3单机部署,实现最简伪集群
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装Nodejs环境
- CentOS8安装Docker,最新的服务器搭配容器使用