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

原文链接:

http://blog.csdn.net/zhangphil/article/details/72926538

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


上层Java代码:
[java]  view plain  copy
  1. package zhangfei.danmaku;  
  2.   
  3. import android.content.res.Configuration;  
  4. import android.graphics.Canvas;  
  5. import android.graphics.Paint;  
  6. import android.graphics.Rect;  
  7. import android.graphics.drawable.Drawable;  
  8. import android.support.v4.content.ContextCompat;  
  9. import android.support.v7.app.AppCompatActivity;  
  10. import android.os.Bundle;  
  11. import android.text.TextPaint;  
  12. import android.util.Log;  
  13. import android.view.View;  
  14.   
  15. import com.github.lzyzsd.randomcolor.RandomColor;  
  16.   
  17. import java.util.HashMap;  
  18.   
  19. import master.flame.danmaku.controller.IDanmakuView;  
  20. import master.flame.danmaku.danmaku.model.BaseDanmaku;  
  21. import master.flame.danmaku.danmaku.model.DanmakuTimer;  
  22. import master.flame.danmaku.danmaku.model.IDanmakus;  
  23. import master.flame.danmaku.danmaku.model.IDisplayer;  
  24. import master.flame.danmaku.danmaku.model.android.DanmakuContext;  
  25. import master.flame.danmaku.danmaku.model.android.SpannedCacheStuffer;  
  26. import master.flame.danmaku.ui.widget.DanmakuView;  
  27.   
  28. public class MainActivity extends AppCompatActivity {  
  29.     private DanmakuView mDanmakuView;  
  30.     private DanmakuContext mContext;  
  31.     private AcFunDanmakuParser mParser;  
  32.   
  33.     private AppCompatActivity mActivity;  
  34.   
  35.     private final String TAG = getClass().getSimpleName();  
  36.   
  37.     private BackgroundCacheStuffer mBackgroundCacheStuffer = new BackgroundCacheStuffer();  
  38.   
  39.     @Override  
  40.     protected void onCreate(Bundle savedInstanceState) {  
  41.         super.onCreate(savedInstanceState);  
  42.         mActivity = this;  
  43.         setContentView(R.layout.activity_main);  
  44.   
  45.         mContext = DanmakuContext.create();  
  46.         mParser = new AcFunDanmakuParser();  
  47.   
  48.         initDanmakuView();  
  49.   
  50.         findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {  
  51.             @Override  
  52.             public void onClick(View view) {  
  53.                 addItems();  
  54.             }  
  55.         });  
  56.     }  
  57.   
  58.     private void initDanmakuView() {  
  59.         // 设置最大显示行数  
  60.         HashMap<Integer, Integer> maxLinesPair = new HashMap<>();  
  61.         maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL, 5); // 滚动弹幕最大显示5行  
  62.         // 设置是否禁止重叠  
  63.         HashMap<Integer, Boolean> overlappingEnablePair = new HashMap<Integer, Boolean>();  
  64.         overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_RL, true);  
  65.         overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_TOP, true);  
  66.   
  67.         mDanmakuView = (DanmakuView) findViewById(R.id.sv_danmaku);  
  68.   
  69.         mContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN, 10)  
  70.                 .setDuplicateMergingEnabled(false)  
  71.                 .setScrollSpeedFactor(1.2f)  
  72.                 .setScaleTextSize(1.0f)  
  73.                 .setCacheStuffer(mBackgroundCacheStuffer, null)  
  74.                 // 绘制背景使用BackgroundCacheStuffer  
  75.                 .setMaximumLines(maxLinesPair)  
  76.                 .preventOverlapping(overlappingEnablePair).setDanmakuMargin(40);  
  77.   
  78.         if (mDanmakuView != null) {  
  79.             mDanmakuView.setCallback(new master.flame.danmaku.controller.DrawHandler.Callback() {  
  80.                 @Override  
  81.                 public void updateTimer(DanmakuTimer timer) {  
  82.                 }  
  83.   
  84.                 @Override  
  85.                 public void drawingFinished() {  
  86.   
  87.                 }  
  88.   
  89.                 @Override  
  90.                 public void danmakuShown(BaseDanmaku danmaku) {  
  91.   
  92.                 }  
  93.   
  94.                 @Override  
  95.                 public void prepared() {  
  96.                     mDanmakuView.start();  
  97.                 }  
  98.             });  
  99.   
  100.             mDanmakuView.setOnDanmakuClickListener(new IDanmakuView.OnDanmakuClickListener() {  
  101.   
  102.                 @Override  
  103.                 public boolean onDanmakuClick(IDanmakus danmakus) {  
  104.                     BaseDanmaku latest = danmakus.last();  
  105.                     if (null != latest) {  
  106.                         return true;  
  107.                     }  
  108.                     return false;  
  109.                 }  
  110.   
  111.                 @Override  
  112.                 public boolean onDanmakuLongClick(IDanmakus danmakus) {  
  113.                     return false;  
  114.                 }  
  115.   
  116.                 @Override  
  117.                 public boolean onViewClick(IDanmakuView view) {  
  118.                     return false;  
  119.                 }  
  120.             });  
  121.   
  122.             mDanmakuView.prepare(mParser, mContext);  
  123.             // mDanmakuView.showFPS(true);  
  124.             mDanmakuView.enableDanmakuDrawingCache(true);  
  125.         }  
  126.     }  
  127.   
  128.     private void addItems() {  
  129.         RandomColor randomColor = new RandomColor();  
  130.   
  131.         int id = (int) (Math.random() * 10) % 3;  
  132.   
  133.         int resId;  
  134.         switch (id) {  
  135.             case 0:  
  136.                 resId = R.drawable.bg_01;  
  137.                 break;  
  138.   
  139.             case 1:  
  140.                 resId = R.drawable.bg_02;  
  141.                 break;  
  142.   
  143.             case 2:  
  144.                 resId = R.drawable.bg_03;  
  145.                 break;  
  146.   
  147.             default:  
  148.                 resId = R.drawable.bg_01;  
  149.                 break;  
  150.         }  
  151.   
  152.         String s = "";  
  153.         int count = (int) (Math.random() * 100) % 10 + 1;  
  154.         for (int i = 0; i < count; i++) {  
  155.             s = s + i;  
  156.         }  
  157.   
  158.         addDanmaKuTextWithBackgroundImage(resId, s, randomColor.randomColor(), false);  
  159.     }  
  160.   
  161.     /** 
  162.      * 绘制背景(自定义弹幕样式) 
  163.      */  
  164.     private class BackgroundCacheStuffer extends SpannedCacheStuffer {  
  165.         @Override  
  166.         public void measure(BaseDanmaku danmaku, TextPaint paint, boolean fromWorkerThread) {  
  167.             danmaku.padding = 50// 在背景绘制模式下增加padding  
  168.             super.measure(danmaku, paint, fromWorkerThread);  
  169.         }  
  170.   
  171.         @Override  
  172.         public void drawBackground(BaseDanmaku danmaku, Canvas canvas, float left, float top) {  
  173.             Object object = danmaku.tag;  
  174.             if (object instanceof DanmakuTag) {  
  175.                 DanmakuTag danmakuTag = (DanmakuTag) object;  
  176.   
  177.                 Drawable drawable = ContextCompat.getDrawable(mActivity, danmakuTag.bitmapResId);  
  178.   
  179.                 float height = danmaku.paintHeight;  
  180.                 float width = danmaku.paintWidth;  
  181.   
  182.                 Rect rect = new Rect(00, (int) width, (int) height);  
  183.                 drawable.setBounds(rect);  
  184.                 drawable.draw(canvas);  
  185.             }  
  186.         }  
  187.   
  188.         @Override  
  189.         public void drawStroke(BaseDanmaku danmaku, String lineText, Canvas canvas, float left,  
  190.                 float top, Paint paint) {  
  191.             // 禁用描边绘制  
  192.         }  
  193.     }  
  194.   
  195.     private void addDanmaKuTextWithBackgroundImage(int bitmap_resId, String msg,  
  196.                                                    int textColor, boolean islive) {  
  197.         BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);  
  198.         if (danmaku == null) {  
  199.             Log.e(TAG, "BaseDanmaku空");  
  200.         }  
  201.   
  202.         DanmakuTag danmakuTag = new DanmakuTag();  
  203.         danmakuTag.bitmapResId = bitmap_resId;  
  204.   
  205.         danmaku.setTag(danmakuTag);  
  206.   
  207.         danmaku.text = "    " + msg + "      ";  
  208.         // danmaku.padding = 5;  
  209.         danmaku.priority = 1// 一定会显示, 一般用于本机发送的弹幕  
  210.         danmaku.isLive = islive;  
  211.         danmaku.setTime(mDanmakuView.getCurrentTime() + 1200);  
  212.         danmaku.textSize = 25f * (mParser.getDisplayer().getDensity() - 0.6f);  
  213.         danmaku.textColor = textColor;  
  214.         danmaku.textShadowColor = 0// 重要:如果有图文混排,最好不要设置描边(设textShadowColor=0),否则会进行两次复杂的绘制导致运行效率降低  
  215.         // danmaku.underlineColor = Color.GREEN;  
  216.         // danmaku.borderColor=new RandomColor().randomColor();  
  217.   
  218.         mDanmakuView.addDanmaku(danmaku);  
  219.     }  
  220.   
  221.     private class DanmakuTag {  
  222.         public int bitmapResId;  
  223.     }  
  224.   
  225.     @Override  
  226.     protected void onPause() {  
  227.         super.onPause();  
  228.         if (mDanmakuView != null && mDanmakuView.isPrepared()) {  
  229.             mDanmakuView.pause();  
  230.         }  
  231.     }  
  232.   
  233.     @Override  
  234.     protected void onResume() {  
  235.         super.onResume();  
  236.         if (mDanmakuView != null && mDanmakuView.isPrepared() && mDanmakuView.isPaused()) {  
  237.             mDanmakuView.resume();  
  238.         }  
  239.     }  
  240.   
  241.     @Override  
  242.     protected void onDestroy() {  
  243.         super.onDestroy();  
  244.         if (mDanmakuView != null) {  
  245.             // dont forget release!  
  246.             mDanmakuView.release();  
  247.             mDanmakuView = null;  
  248.         }  
  249.     }  
  250.   
  251.     @Override  
  252.     public void onBackPressed() {  
  253.         super.onBackPressed();  
  254.         if (mDanmakuView != null) {  
  255.             // dont forget release!  
  256.             mDanmakuView.release();  
  257.             mDanmakuView = null;  
  258.         }  
  259.     }  
  260.   
  261.     @Override  
  262.     public void onConfigurationChanged(Configuration newConfig) {  
  263.         super.onConfigurationChanged(newConfig);  
  264.         if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {  
  265.             mDanmakuView.getConfig().setDanmakuMargin(20);  
  266.         } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {  
  267.             mDanmakuView.getConfig().setDanmakuMargin(40);  
  268.         }  
  269.     }  
  270. }  


代码运行结果:




附录:
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  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值