精华内容
下载资源
问答
  • android开源弹幕库,强力推荐

    热门讨论 2014-06-19 16:17:18
    一套很完整的android开源库,弹幕的绘制和获取都封装得很完整,可直接使用
  • Android弹幕框架 黑暗火焰使

    千次阅读 2016-10-20 11:25:13
    笑谈风云,一语定乾坤。大家好,我是皖江。 今天我将分享由BiliBili开源的Android弹幕框架(DanmakuFlameMaster)的学习经验。

    笑谈风云,一语定乾坤。大家好,我是皖江。

    今天我将分享由BiliBili开源的Android弹幕框架(DanmakuFlameMaster)的学习经验。

    我是将整个框架以model的形式引入项目中的,这样更方便的观察源码。也可以通过依赖的方式注入进来

    dependencies {
        compile 'com.github.ctiao:DanmakuFlameMaster:0.5.3'
    }

    先放一下我要做成的效果图:


    页面分析

    从上图来看,整个UI分成了三层。最下面是视频层,中间是弹幕层,顶层是控制层。现在市场上主流的视频直播软件大多都是这样分层的,不同的是直播类的话,可能还会再多一层交互层,显示签到信息、礼物信息什么的。

    既然是分层的话,我就直接用FrameLayout帧布局来实现了。贴一下我的布局文件:

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <VideoView
            android:id="@+id/vv_video"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
        <master.flame.danmaku.ui.widget.DanmakuView
            android:id="@+id/sv_danmaku"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
        <include android:id="@+id/media_controller"
            android:layout_width="match_parent"
            android:layout_height="fill_parent"
            layout="@layout/media_controller" />
    
    </FrameLayout>
    控制层的布局:

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    
        <LinearLayout
            android:gravity="center_vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:background="#8acc22dd" >
    
            <Button
                android:layout_weight="1"
                android:id="@+id/rotate"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:text="@string/rotate" />
    
            <Button
                android:layout_width="0dp"
                android:layout_weight="1"
                android:id="@+id/btn_hide"
                android:layout_height="wrap_content"
                android:text="@string/hide_danmaku" />
    
            <Button
                android:id="@+id/btn_show"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content"
                android:text="@string/show_danmaku" />
    
            <Button
                android:id="@+id/btn_pause"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content"
                android:text="@string/pause_danmaku" />
    
            <Button
                android:id="@+id/btn_resume"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content"
                android:text="@string/resume_danmaku" />
    
            <Button
                android:id="@+id/btn_send"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content"
                android:text="@string/send_danmaku" />
    
            <Button
                android:id="@+id/btn_send_image_text"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content"
                android:text="@string/send_danmaku_image_text" />
            
            <Button
                android:id="@+id/btn_send_danmakus"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content"
                android:text="@string/send_danmakus" />
        </LinearLayout>
    
    </FrameLayout>

    写完布局,先写一个初始化的方法:

            //设置最大行数
            HashMap<Integer,Integer> maxLinesPair = new HashMap<>();
            maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL,5);//滚动弹幕最大显示5行
            //设置是否禁止重叠
            HashMap<Integer, Boolean> overlappingEnablePair = new HashMap<>();
            overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_RL, true);
            overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_TOP, true);
            mDanmakuContext = DanmakuContext.create();//初始化上下文
            mDanmakuContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN,3);//设置弹幕类型
            mDanmakuContext.setDuplicateMergingEnabled(false);//设置是否合并重复弹幕
            mDanmakuContext.setScrollSpeedFactor(1.2f);//设置弹幕滚动速度
            mDanmakuContext.setScaleTextSize(1.2f);//设置弹幕字体大小
            mDanmakuContext.setCacheStuffer(new SpannedCacheStuffer(),mCacheStufferAdapter);//设置缓存绘制填充器 图文混排使用SpannedCacheStuffer  
            mDanmakuContext.setMaximumLines(maxLinesPair);//设置最大行数
            mDanmakuContext.preventOverlapping(overlappingEnablePair); //设置是否禁止重叠
            mParser = createParser(this.getResources().openRawResource(R.raw.comments));//加载弹幕资源文件
            mDvDanmaku.prepare(mParser, mDanmakuContext);
            mDvDanmaku.showFPS(true);
            mDvDanmaku.enableDanmakuDrawingCache(true);


    再贴一下绘制填充器的实现,主要实现了将图片和文字排列在一起的效果

        private SpannableStringBuilder createSpannable(Drawable drawable) {
            String text = "bitmap";
            SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(text);
            ImageSpan span = new ImageSpan(drawable);
            spannableStringBuilder.setSpan(span, 0, text.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
            spannableStringBuilder.append("图文混排");
            spannableStringBuilder.setSpan(new BackgroundColorSpan(Color.parseColor("#8A2233B1")), 0, spannableStringBuilder.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
            return spannableStringBuilder;
        }

    在BaseDanmaku这个类下,定义了弹幕的基本运动形式:TYPE_SCROLL_RL、 TYPE_SCROLL_LR、TYPE_FIX_TOP、TYPE_FIX_BOTTOM和TYPE_SPECIAL。也就是从右入左出、左入右出(逆向弹幕)、顶部弹幕、底部弹幕以及高级弹幕。(除此之外还有脚本弹幕)

    在初始化的时候,需要传入一个特有的弹幕上下文DanmukuContext,通过上下文来初始化一些设置。弹幕资源是保存在xml文件下的,大致格式如下:

    .

    <i>
        <chatserver>chat.bilibili.com</chatserver>
        <chatid>2962351</chatid>
        <mission>0</mission>
        <maxlimit>1500</maxlimit>
        <source>k-v</source>
        <d p="145.91299438477,1,25,16777215,1422201001,0,D6673695,757075520">我从未见过如此厚颜无耻之人</d>
    </i>
    头信息不需要太多关注,来看看d标签下p对应参数的具体意义:

    第一个:弹幕出现的时间

    第二个:弹幕类型(1、从右至左;6、从左至右;5、顶部弹幕;4、底部弹幕;7、高级弹幕;8、脚本弹幕’)

    第三个:字号

    第四个:颜色

    第五个:时间戳

    第六个:弹幕池ID

    第七个:用户hash值

    第八个:弹幕id

    以下是弹幕具体解析代码


        /**
         * 从弹幕文件中提起弹幕
         * @param stream
         * @return
         */
        private BaseDanmakuParser createParser(InputStream stream) {
            if (stream == null) {
                return new BaseDanmakuParser() {
                    @Override
                    protected Danmakus parse() {
                        return new Danmakus();
                    }
                };
            }
            ILoader loader = DanmakuLoaderFactory.create(DanmakuLoaderFactory.TAG_BILI);//创建一个BiliDanmakuLoader实例来加载弹幕流文件
            try {
                loader.load(stream);
            } catch (IllegalDataException e) {
                e.printStackTrace();
            }
            BaseDanmakuParser parser = new BiliDanmukuParser();//弹幕解析者
            IDataSource<?> dataSource = loader.getDataSource();
            parser.load(dataSource);
            return parser;
        }

    具体解析方案:

                String tagName = localName.length() != 0 ? localName : qName;
                tagName = tagName.toLowerCase(Locale.getDefault()).trim();
                if (tagName.equals("d")) {
                    String pValue = attributes.getValue("p");
                    // parse p value to danmaku
                    String[] values = pValue.split(",");
                    if (values.length > 0) {
                        long time = (long) (Float.parseFloat(values[0]) * 1000); // 出现时间
                        int type = Integer.parseInt(values[1]); // 弹幕类型
                        float textSize = Float.parseFloat(values[2]); // 字体大小
                        int color = Integer.parseInt(values[3]) | 0xFF000000; // 颜色
                        item = mContext.mDanmakuFactory.createDanmaku(type, mContext);
                        if (item != null) {
                            item.setTime(time);
                            item.textSize = textSize * (mDispDensity - 0.6f);
                            item.textColor = color;
                            item.textShadowColor = color <= Color.BLACK ? Color.WHITE : Color.BLACK;
                        }
                    }
                }
    弹幕资源加载完毕后,就调用mDvDanmuku的prepare()方法,执行准备。当准备完毕的时候,就会调用DrawHandler.CallBack()回调中的prepared方法。然后在这个prepared方法中正式让弹幕启动。调用顺序如下:

    mDvDanmaku.prepare(mParser, mDanmakuContext);//传入解析完成的弹幕和上下文

    然后执行DanmukuView下的prepare()方法

        private void prepare() {
            if (handler == null)
                handler = new DrawHandler(getLooper(mDrawingThreadType), this, mDanmakuVisible);//创建一个Handler
        }
    通过这个Handler来实现进程间的通讯

            handler.setConfig(config);
            handler.setParser(parser);
            handler.setCallback(mCallback);
            handler.prepare();-》会让handler发送一个message  去执行正真的准备
    DrawHandler中有一个回调
        public interface Callback {
            public void prepared();
    
            public void updateTimer(DanmakuTimer timer);
    
            public void danmakuShown(BaseDanmaku danmaku);
    
            public void drawingFinished();
    
        }
    真正的准备

    mTimeBase = SystemClock.uptimeMillis();
                    if (mParser == null || !mDanmakuView.isViewReady()) {//没有准备好,延时0.1秒后再执行
                        sendEmptyMessageDelayed(PREPARE, 100);
                    } else {
                        prepare(new Runnable() {
                            @Override
                            public void run() {
                                pausedPosition = 0;
                                mReady = true;
                                if (mCallback != null) {
                                    mCallback.prepared();
                                }
                            }
                        });
                    }
    以上是弹幕View的启动调用流程。
    那么,怎么添加弹幕捏?元芳,你怎么看?(TM我怎么知道我怎么看)看下面
        private void addDanmaku(boolean islive) {
            BaseDanmaku danmaku = mDanmakuContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);//添加一条从右到左的滚动弹幕
            if (danmaku == null || mDvDanmaku == null) {
                return;
            }
            danmaku.text = "这是一条弹幕" + System.nanoTime();
            danmaku.padding = 5;
            danmaku.priority = 0;  // 可能会被各种过滤器过滤并隐藏显示  设置为1的话,就一定会显示  适用于本机发送的弹幕
            danmaku.isLive = islive;
            danmaku.setTime(mDvDanmaku.getCurrentTime() + 1200);
            danmaku.textSize = 25f * (mParser.getDisplayer().getDensity() - 0.6f);
            danmaku.textColor = Color.RED;//默认设置为红色字体
            danmaku.textShadowColor = Color.WHITE;
            danmaku.borderColor = Color.GREEN;//为了区别其他弹幕与自己发的弹幕,再给自己发的弹幕加上边框
            mDvDanmaku.addDanmaku(danmaku);
        }

    以上,就是 黑暗火焰使基本使用方法。

    展开全文
  • 主要介绍了Android弹幕框架黑暗火焰使基本使用方法,需要的朋友可以参考下。今天我将分享由BiliBili开源的Android弹幕框架(DanmakuFlameMaster)的学习经验,感兴趣的朋友一起看看吧
  • Android 弹幕可用开源框架

    千次阅读 2017-06-23 10:51:31
    1 黑暗火焰https://github.com/Bilibili/DanmakuFlameMaster2 开源组件https://github.com/linsea/OpenDanmaku
    展开全文
  • 基于弹幕情感分析的直播高光时刻判断模型设计 数据清洗与初步 基于词典的句子情感值计算模型 基于机器学习的片段情感分析与高光时刻判断模型 系统设计与实现 直播弹幕情感分析与高光检测系统 技术架构 前置:...
  • 所以,后续公众号会慢慢跟大家推荐一些Java开源项目给大家,一起学习成长~ 项目简介 实现B站弹幕:现在很多人都喜欢在B站上看视频或者学习,因为B站上的弹幕,算是视频领域的先驱了,现在感觉弹幕是每个视频平台的...

    嗨喽!Java后端编程的各位小伙伴们,由于公众号做了乱序推送改版,为了保证公众号的推文能够第一时间及时送达到大家手上,大家记得将公众号 加星标置顶 ,公众号每天会送上Java技术干货推文 !

    上篇推文:

    开源 SpringBoot 商城系统,真香!

    刚学习Java的同学,如果想要快速获得项目经验,最好的途径就是学习前辈的开源项目。编程君在大学也是去GitHub上搜索那些关注比较多的Java项目下来研究和学习,慢慢的懂得了一整套的开发所需要掌握的知识点和技能 。所以,后续公众号会慢慢跟大家推荐一些Java开源项目给大家,一起学习成长~

    项目简介

    实现B站弹幕:现在很多人都喜欢在B站上看视频或者学习,因为B站上的弹幕,算是视频领域的先驱了,现在感觉弹幕是每个视频平台的标配了,没有弹幕功能,看视频是没有灵魂的。

    作为程序员,如果哪天产品经理要求要实现这样类似的一个弹幕功能,你有想法了吗?如果没有也没事,今天给大家推荐一款GitHub开源项目就是关于实现弹幕的功能的,大家可以参考作者怎么实现这个功能的。

    项目框架

    这个开源项目是基于 CSS3 Animation,使用 React 构建,可扩展,高性能。该项目具备以下4个特性:

    • 支持传入 React 组件,灵活控制弹幕内容和 UI,并提供一个默认样式组件:<StyledBullet/>

    • 弹幕屏幕管理:清屏,暂停,隐藏(后续可能会加入针对单个弹幕的控制)

    • 弹幕动画参数化:运动函数(匀速/ease/步进/cubic-bezier)、时长(秒)、循环次数、延迟等

    • 鼠标悬浮弹幕暂停

    今天给大家介绍的这款实现类似B站弹幕的开源项目,如果大家有兴趣的话,可以关注下面公众号,后台回复对应关键词获取。

    项目下载

    关注后,发送关键词:【103

    觉得内容还不错的话,一键三连支持下呗

    展开全文
  • Android弹幕实现:基于B站弹幕开源系统(2)在附录1的基础上,模拟实现一种实际开发的应用场景:从网络中不间断的周期取弹幕数据,这些弹幕数据往往是批量的,然后把这些从网络中取到的批量数据逐个的显示出来。...
    

    Android弹幕实现:基于B站弹幕开源系统(2)

    在附录1的基础上,模拟实现一种实际开发的应用场景:从网络中不间断的周期取弹幕数据,这些弹幕数据往往是批量的,然后把这些从网络中取到的批量数据逐个的显示出来。注意本例中的Handler和线程安全队列ConcurrentLinkedQueue的使用。
    Java代码:

    package zhangphil.danmaku;
    
    import android.app.Activity;
    import android.graphics.Color;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.support.annotation.NonNull;
    import android.text.TextUtils;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.concurrent.ConcurrentLinkedQueue;
    import java.util.concurrent.ScheduledThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    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.DanmakuContext;
    import master.flame.danmaku.ui.widget.DanmakuView;
    
    public class MainActivity extends Activity {
    
        private DanmakuView mDanmakuView;
        private DanmakuContext mContext;
        private AcFunDanmakuParser mParser;
    
        private ScheduledThreadPoolExecutor mScheduledThreadPoolExecutor = null;
        private ConcurrentLinkedQueue<String> mQueue = null;
    
        private final int WHAT_GET_LIST_DATA = 0xffa01;
        private final int WHAT_DISPLAY_SINGLE_DANMAKU = 0xffa02;
    
        private final int[] colors = {Color.RED, Color.YELLOW, Color.BLUE, Color.GREEN, Color.CYAN, Color.DKGRAY};
    
        private Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
    
                switch (msg.what) {
                    case WHAT_GET_LIST_DATA:
                        handler.removeMessages(WHAT_GET_LIST_DATA);
    
                        ArrayList lists = (ArrayList) msg.obj;
                        if (lists != null && !lists.isEmpty()) {
                            mQueue.addAll(lists);
    
                            if (!mQueue.isEmpty())
                                handler.sendEmptyMessage(WHAT_DISPLAY_SINGLE_DANMAKU);
                        }
    
                        break;
    
                    case WHAT_DISPLAY_SINGLE_DANMAKU:
                        handler.removeMessages(WHAT_DISPLAY_SINGLE_DANMAKU);
                        displayDanmaku();
                        break;
                }
            }
        };
    
        private void displayDanmaku() {
            String s = mQueue.poll();
            if (!TextUtils.isEmpty(s)) {
                addDanmaku(s, true);
            }
    
            if (!mQueue.isEmpty())
                handler.sendEmptyMessageDelayed(WHAT_DISPLAY_SINGLE_DANMAKU, (long) (Math.random() * 400) + 100);
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mQueue = new ConcurrentLinkedQueue<>();
            mDanmakuView = (DanmakuView) findViewById(R.id.danmakuView);
            init();
    
            mScheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1);
            GetDanmakuMessageTask mTask = new GetDanmakuMessageTask();
            //延迟0秒执行,每隔若干秒周期执行一次任务
            mScheduledThreadPoolExecutor.scheduleAtFixedRate(mTask, 0, 5, TimeUnit.SECONDS);
    
            Button show = (Button) findViewById(R.id.show);
            Button hide = (Button) findViewById(R.id.hide);
            Button sendText = (Button) findViewById(R.id.sendText);
            Button pause = (Button) findViewById(R.id.pause);
            Button resume = (Button) findViewById(R.id.resume);
            Button clear = (Button) findViewById(R.id.clear);
    
            show.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mDanmakuView.show();
                }
            });
    
            hide.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mDanmakuView.hide();
                }
            });
    
            sendText.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //每点击一次按钮发送一条弹幕
                    sendTextMessage();
                }
            });
    
            pause.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mDanmakuView.pause();
                }
            });
    
            resume.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mDanmakuView.resume();
                }
            });
    
            clear.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    clearDanmaku();
                }
            });
        }
    
        /**
         * 假设该线程任务模拟的就是从网络中取弹幕数据的耗时操作
         * 
         */
        private class GetDanmakuMessageTask implements Runnable {
            @Override
            public void run() {
                try {
                    Thread.sleep((long) (Math.random() * 1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                ArrayList<String> danmakuLists = new ArrayList<>();
                int count = (int) (Math.random() * 100);
                for (int i = 0; i < count; i++) {
                    danmakuLists.add("批量数据" + i + " - " + Math.random());
                }
    
                if (!danmakuLists.isEmpty()) {
                    Message msg = handler.obtainMessage();
                    msg.what = WHAT_GET_LIST_DATA;
                    msg.obj = danmakuLists;
                    handler.sendMessage(msg);
                }
            }
        }
    
    
        private void clearDanmaku() {
            mQueue.clear();
            mDanmakuView.clearDanmakusOnScreen();
        }
    
        private void init() {
            mContext = DanmakuContext.create();
    
            // 设置最大显示行数
            HashMap<Integer, Integer> maxLinesPair = new HashMap<>();
            maxLinesPair.put(BaseDanmaku.TYPE_SCROLL_RL, 8); // 滚动弹幕最大显示5行
    
            // 设置是否禁止重叠
            HashMap<Integer, Boolean> overlappingEnablePair = new HashMap<>();
            overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_RL, true);
            overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_TOP, true);
    
            mContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN, 10) //描边的厚度
                    .setDuplicateMergingEnabled(false)
                    .setScrollSpeedFactor(1.2f) //弹幕的速度。注意!此值越小,速度越快!值越大,速度越慢。// by phil
                    .setScaleTextSize(1.2f)  //缩放的值
                    //.setCacheStuffer(new SpannedCacheStuffer(), mCacheStufferAdapter) // 图文混排使用SpannedCacheStuffer
    //        .setCacheStuffer(new BackgroundCacheStuffer())  // 绘制背景使用BackgroundCacheStuffer
                    .setMaximumLines(maxLinesPair)
                    .preventOverlapping(overlappingEnablePair);
    
            mParser = new AcFunDanmakuParser();
            mDanmakuView.prepare(mParser, mContext);
    
            //mDanmakuView.showFPS(true);
            mDanmakuView.enableDanmakuDrawingCache(true);
    
            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) {
                        Log.d("弹幕文本", "danmakuShown text=" + danmaku.text);
                    }
    
                    @Override
                    public void prepared() {
                        mDanmakuView.start();
                    }
                });
            }
        }
    
        private void sendTextMessage() {
            addDanmaku("zhangphil @ csdn : " + System.currentTimeMillis(), true);
        }
    
        private void addDanmaku(CharSequence txt, boolean islive) {
            BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
            if (danmaku == null || mDanmakuView == null) {
                return;
            }
    
            danmaku.text = txt;
            danmaku.padding = 5;
            danmaku.priority = 0;  // 可能会被各种过滤器过滤并隐藏显示
            danmaku.isLive = islive;
            danmaku.setTime(mDanmakuView.getCurrentTime() + 1200);
            danmaku.textSize = 20f * (mParser.getDisplayer().getDensity() - 0.6f); //文本弹幕字体大小
            danmaku.textColor = getRandomColor(); //文本的颜色
            danmaku.textShadowColor = getRandomColor(); //文本弹幕描边的颜色
            //danmaku.underlineColor = Color.DKGRAY; //文本弹幕下划线的颜色
            danmaku.borderColor = getRandomColor(); //边框的颜色
    
            mDanmakuView.addDanmaku(danmaku);
        }
    
        @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;
            }
    
            if (mScheduledThreadPoolExecutor != null)
                mScheduledThreadPoolExecutor.shutdown();
        }
    
        /**
         * 从一系列颜色中随机选择一种颜色
         *
         * @return
         */
        private int getRandomColor() {
            int i = ((int) (Math.random() * 10)) % colors.length;
            return colors[i];
        }
    }


    代码运行结果:



    附录:
    1,《Android弹幕实现:基于B站弹幕开源系统(1)》链接地址:http://blog.csdn.net/zhangphil/article/details/68067100
    2,《Java ConcurrentLinkedQueue队列线程安全操作》链接地址:http://blog.csdn.net/zhangphil/article/details/65936066

    展开全文
  • 弹幕框架DanmakuFlameMaster简单分析

    千次阅读 2018-06-29 18:35:06
    随着B站逐渐崛起,其开源弹幕项目DanmakuFlameMaster应用场景也越来越多。我也是在一次偶然机会下发现了这个项目,被其惊艳的效果震撼。以前我就对弹幕技术很感兴趣,可能是因为B站动漫看多,几乎每一部番都是漫天的...
  • Android弹幕实现:基于B站弹幕开源系统(4)-重构 弹幕在视频播放的APP中比较常见,但是逻辑比较复杂,现在在附录1,2,3的基础上,我再次对弹幕进行抽象和重构,把弹幕从底向上抽象成不同的层,便于复用。 第一步,...
  • 弹幕框架

    千次阅读 2017-11-21 16:50:23
    弹幕框架DanmakuFlameMaster浅要分析
  • 实时弹幕系统的设计与实现

    千次阅读 2018-12-13 14:44:27
    发现在GitHub上开源了一个JS弹幕模块核心CommentCoreLibrary,慢慢开始学习Node.js的一套。原来是比较做后台开发的,也是第一次做这样的分享,请大家多多指教啦…… 一、Express Express是Node...
  • Akari.biliScript是一个针对BiliPlayer的开源弹幕艺术辅助框架。这个辅助框架根据设计允许进度条跳转,并会将内容自动匹配到播放器窗口上。 原repo 我Fork这个repo的可能目的: 创建一个较为平易近人的引导教程文档...
  • Android开发常用开源框架

    万次阅读 多人点赞 2018-08-22 11:37:41
    Android开源框架系列 Android开源项目 Android开发常用开源框架2 Android开发常用开源框架3 GitHub上最火的Android开源项目,所有开源项目都有详细资料和配套视频 2017年伊始,你需要尝试的25...
  • Android - 弹幕实现原理(附Demo源码)

    千次阅读 2018-05-30 15:11:39
    二、弹幕原理的简单解析 1.我们先来做些准备工作。 (1)我们可能会需要一个视频(我在这里找了一个mp4格式的视频,并放在了res/raw目录下面,因为音频和视频文件放在其它目录(例如assets资源目录)下会导致无法...
  • Android 直播 弹幕

    千次阅读 2019-08-05 11:24:12
    Android 直播 弹幕
  • Android集成B站弹幕库Danmaku

    千次阅读 2017-08-14 13:28:18
    弹幕库是B站开发的一款开源弹幕库引擎,非常火爆,号称烈焰弹幕使! 项目的github开源网址 特点 使用多种方式(View/SurfaceView/TextureView)实现高效绘制 B站xml弹幕格式解析 基础弹幕精确还原绘制 支持mode7...
  • iOS开源弹幕库BarrageRenderer

    千次阅读 2016-04-07 13:37:30
    这是一个 iOS 上的开源弹幕渲染库. 弹幕实质是多个精灵的时间上的渲染方式. PC/Web上已经有很成熟的解决方案了; Android上比较有名的是BiliBili开源的DanmakuFlameMaster, 但是开源社区尚没有比较好的
  • 由于博主是个忠实的英雄联盟粉丝,所以经常观看一些明星大神的直播。而一谈到直播,肯定会看到满屏幕飘来飘去的弹幕。...那咱们就百度一下吧,看看有什么好用的弹幕插件,现在开源的东西那么多。 ...
  • 给定up主uid和用户uid,爬取用户在该up主所有视频中发的所有弹幕 需求拆解 获取up主所有视频 打开b站,随便搜索一个up主,打开所有视频页面,f12看异步请求就一目了然了 接口地址:...
  • 最近项目中需要添加弹幕功能,就用了B站的开源框架DanmakuFlameMaster。本文从源码分析了一下弹幕动起来的逻辑。
  • 支持弹幕 支持基本的拖动,声音、亮度调节 支持边播边缓存 支持视频本身自带rotation的旋转(90,270之类),重力旋转与手动旋转的同步支持 支持列表播放,直接添加控件为封面,列表全屏动画,视频加载速度,列表小...
  • Android优秀开源框架

    千次阅读 2019-09-12 16:24:21
    Android优秀开源框架介绍开源框架来源说明1. okhttp2. retrofit3. MPAndroidChart4. glide5. xxx 开源框架来源说明 本文中介绍框架来源,根据github android开源框架星数排名,取前80。 1. okhttp 简介: ...
  • 播放器+弹幕自定义

    2020-06-02 11:21:37
    饺子播放器的自定义(弹幕) 自定义包含弹幕的播放器准备工作 需要的开源库 1.饺子视频播放器地址(主角) 2.烈焰弹幕使地址 3.eventBus地址 引入饺子播放器后,编写类继承饺子播放器的JzvdStd class MyJzvd ...
  • 前言最近做项目需要用到一个弹幕的效果,本来一开始准备自己去捣鼓捣鼓实现一下,后来一看有特别好用的BiliBili的开源库DanmakuFlameMaster,所以就拿来用了,简单的使用就不说了,看看源码,网上有教程,都能跑起来...
  • 首页博客学院下载GitChatTinyMind论坛问答商城VIP活动招聘ITeyeCSTO写博客发Chatliangyalong_1314的博客RSS订阅原Android 自定义控件-------弹幕置顶2018年05月23日 16:51:19阅读数:39Demo下载地址 ...
  • 各种Android UI开源框架

    万次阅读 多人点赞 2016-12-06 11:22:20
    自己总结的Android开源项目及库。 github排名 https://github.com/trending,github搜索:https://github.com/search Android库学习收集QQ群: 339129051 欢迎入群。 目录 UI UI卫星菜单节选器下拉刷新模糊...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,506
精华内容 1,002
关键字:

弹幕开源框架