仿视频网站弹幕效果

news/2024/5/8 15:53:20/文章来源:https://blog.csdn.net/jimbo_xiaohei/article/details/80177074

一、需求

开发一个类似bilibili的视频弹幕效果。网上有bilibili的开源项目。那么我们要实现一个简易的,应该怎么办呢?
有办法的,先看效果:

弹幕.png

二、分析

最直接的办法是自定义一个ScreenView作为幕布,然后绘制一个个的子弹(每一个view,暂且这么叫),但是想想一个个的draw,效率应该不高。
换成自定义ViewGroup,然后创建一个个的子弹view add进去,确定子弹的left和top就好了,然后view自己去执行动画,起始和终点位置也很好确定:

起点:就是屏幕宽度
终点:距屏幕左边子弹(每一个view,暂且这么叫)宽度的长度

子弹的left很好确定,就是屏幕宽度,但是top怎么办?
我们可以按幕布的高度去随机一个值,但是随机值得话有风险,子弹会重叠。
那就先按子弹的高度去划分屏幕,把屏幕分成固定的行数,然后判断随机的值落在哪一行。
还有一个问题,子弹和子弹之间是有空隙的,随机值落在空隙之间怎么办?
这个很好处理,落在空隙之间的数值全部计为-1,只要是-1就重新random。
说了这么多一步步的看代码怎么实现吧。

三、代码实现

3.1 子弹view

别的不管,先画布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="horizontal"android:layout_width="wrap_content"android:layout_height="36dp"android:background="@drawable/bg_bullet_view"android:padding="4dp"android:gravity="center_vertical"><ImageView
        android:id="@+id/iv_head_view"android:layout_width="28dp"android:layout_height="28dp"android:src="@mipmap/headview"/><TextView
        android:id="@+id/tv_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="很好看"android:textSize="14sp"android:layout_marginLeft="4dp"/><ImageView
        android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@mipmap/zan"android:layout_marginLeft="10dp"/><TextView
        android:id="@+id/tv_zan"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="254"android:textSize="12sp"android:layout_marginRight="6dp"android:layout_marginLeft="2dp"/>
</LinearLayout>

一个头像,一个标题加上一个赞数,很常见的样式。再看子弹view的代码:

public class BulletView extends LinearLayout {private ImageView ivHeadView;           //头像private TextView tvTitle;               //标题private TextView tvZan;                 //赞数private ObjectAnimator animator;        //动画private float animatedValue;            //记录当前动画的移动值private Bullet bullet;                  //子弹数据private int line;                       //记录所在的行数private Point startPoint;               //开始点private Point endPoint;                 //终点private OnAllShowInScreen listener;     //动画监听private boolean hasClear = false;       //标记  标记是否移除了起始位置的子弹
}

这里最重要的是一个属性动画属性,就是说每一个子弹都有一个动作,从屏幕右边移动到屏幕左边。先不管动画,先看怎么把子弹添加进幕布。

3.2 幕布的创建

在幕布里用到一个生产者消费者的知识,我们需要开启一个线程相当于是消费者,一直消费子弹,而主线程就要不断的添加子弹,类似于生产者。
主线程我们可以手动控制添加,不需要等待,但是消费者不一样,没有子弹的时候,他需要等待,我们添加了新的子弹去唤醒他消费,每消费一个子弹,我们就往幕布增加一个子弹view。
这是第一种需要等待的情况,还有一种是子弹过多,屏幕上所有的行数都有子弹正在执行开始动画的时候,消费子弹的也需要等待。注意是开始动画而不是所有行数都有动画的时候,这是为了避免新添加的子弹view覆盖正在执行开始动画的子弹view。
挑主要的代码看:

public class BulletScreenView extends FrameLayout {...private List<Bullet> bullets = new ArrayList<>();           //子弹仓库private List<Rect> rightRect = new ArrayList<>();           //随机的高度值所在的rectprivate List<List<Bullet>> lines = new ArrayList<>();       //每一行正在执行开始动画的子弹private List<Bullet> lineBullets = new ArrayList<>();       //所有行正在执行开始动画的子弹// 锁private final Lock lock = new ReentrantLock();// 消费者状态private final Condition consumer = lock.newCondition();...
}

幕布view中这四个变量非常重要,第四个和第三也不是重复,避免了大量遍历。
一个个看,bullets就是存储所有添加进来的子弹,看暴漏的方法:

    /*** 添加子弹* @param bs*/public void addBullet(List<Bullet> bs) {lock.lock();bullets.addAll(bs);consumer.signal();lock.unlock();}

前后加锁,只要有新子弹进来就去通知消费者线程,看消费者线程做了啥:

    /*** 消耗线程*/public class ConsumerThread extends Thread {@Overridepublic void run() {while (true){lock.lock();while (bullets.size() == 0 || lineBullets.size() == lineCount) {try {consumer.await();} catch (InterruptedException e) {e.printStackTrace();}}Bullet bullet = bullets.remove(0);initBulletView(bullet);lineBullets.add(bullet);handler.obtainMessage(0, bullet).sendToTarget();lock.unlock();}}}

死循环里面,还是加锁,然后while下的判断条件,当子弹仓库为空或者所有行开始动画个数等于个数的时候,消费者进入等待,否则就去取第一个子弹,然后初始化子弹view,这个时候需要把这个子弹view添加进所有行开始动画的lineBullets里面记录下来,还发出去一个handler消息。
1. 初始化子弹view做了啥;
2. handler做了啥。
首先看第一个代码:

    /*** 初始化子弹view* @param bullet*/private void initBulletView(Bullet bullet) {//随机高度double randomHeight = Math.random() * mHeight;//判断在哪一行int currentLine = seekLine(randomHeight);//如果行数等于-1 说明不合法 循环取while (currentLine == -1){randomHeight = Math.random() * mHeight;currentLine = seekLine(randomHeight);}//如果这一行没有开始动画,直接初始化子弹if (lines.get(currentLine).size() == 0) {BulletView bulletView = new BulletView(mContext);LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);// 找到当前行的top值params.topMargin = seekLineTop(randomHeight);bulletView.setLine(currentLine);//设置动画监听bulletView.setListener(new BulletView.OnAllShowInScreen() {@Overridepublic void onAllShow(BulletView bulletView) {lock.lock();int measuredWidth1 = bulletView.getMeasuredWidth();// 如果动画执行到 子弹完全暴漏在幕布上 的位置,那么这一行的 开始动画记录要清掉了if (bulletView.getAnimatedValue() < mWidth - measuredWidth1) {//是否清除过了,因为动画后续会一直进入这里  但是清除只需要清一次if(!bulletView.isHasClear()) {int line = bulletView.getLine();//当前行记录动画清除lines.get(line).clear();//总开始动画记录也清掉lineBullets.remove(bulletView.getBullet());consumer.signal();bulletView.setHasClear(true);}}lock.unlock();}});bulletView.setLayoutParams(params);// 记录 当前行 开始动画lines.get(currentLine).add(bullet);bullet.setBulletView(bulletView);} else {//否则调用自己 重新选择行数initBulletView(bullet);}}

动画回调里面有一个consumer.signal();就是一旦有行数空一个位置出来,就去通知消费者送一个子弹过来。
那么handler做了啥呢?

    /*** 主线程刷新UI*/private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case 0:Bullet obj = (Bullet) msg.obj;BulletView bulletView = obj.getBulletView();bulletView.setData(obj);int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);bulletView.measure(spec, spec);int measuredWidth = bulletView.getMeasuredWidth();bulletView.startAnim(new Point(mWidth, y), new Point(-measuredWidth, y), 5000);addView(bulletView);break;}}};

设置数据之后,计算出这时候子弹的长度就比较精确了。然后开启子弹的动画,并把子弹add进布局。子弹的view我们已经记录在子弹里面了。到这里就是完整的思路了。

更多代码看GayHub,有兴趣试一试。

很多视频的弹幕触摸还有暂停,松开继续跑的需求没加了,用记录的动画位置就可以做到,不写了。感谢看到这里。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_886423.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

有关采用Filter:实现网站自动登录功能模块

网站自动登录操作分析,我以CSDN用户登录功能为例说明, 1.进入csdn网站的登录界面 地址: CSDN用户登录界面 界面效果如下: 2.输入正确的用户名和密码,并且勾选上 下次自动登录功能 3.点击登录,如果成功登录,就会跳转到登陆成功的界面. 4.如果你再去点击CSDN用户登录界面 看看什…

.NET技术+25台服务器怎样支撑世界第54大网站

英文原文&#xff1a; StackOverflow Update: 560M Pageviews A Month, 25 Servers, And Its All About Performance StackOverflow 是一个 IT 技术问答网站&#xff0c;用户可以在网站上提交和回答问题。当下的 StackOverflow 已拥有 400 万个用户&#xff0c;4000 万个回答&…

说说大型高并发高负载网站的系统架构

转载请保留出处&#xff1a;俊麟 Michael’s blog (http://www.toplee.com/blog/?p71)Trackback Url : http://www.toplee.com/blog/wp-trackback.php?p71 我在CERNET做过拨号接入平台的搭建&#xff0c;而后在Yahoo&3721从事过搜索引擎前端开发&#xff0c;又在MOP处理过…

更改Wamp下网站地址栏图标

大家应该遇到这样一个问题&#xff0c;我们利用wamp做服务器运行网页的时候&#xff0c;网页地址栏显示的图标一直是wampserver默认的图标&#xff0c;想改一下怎么办呢&#xff1f; 问题如下&#xff1a; 就是这些图标&#xff0c;如何自定义自己的图标&#xff0c;而不是…

炫酷的个人功能网站

有空把自己之前的网站修缮了下&#xff0c;首先把pc端&#xff0c;手机端兼容问题解决了&#xff0c;之前的没有响应式框架&#xff0c;第二&#xff0c;跨域问题解决了&#xff0c;之前最重要的一些页面总是出不来&#xff0c;现在可以了&#xff0c;还有就是不小心把数据库删…

一个炫酷的个人网站带后台

该demo下线了&#xff0c;如果还有需要源码的请找我&#xff0c;工作一年后我总结模块&#xff0c;新上线了一个系统&#xff0c;欢迎大家查阅指教&#xff01; 点击进入系统http://zengchenglong.online:8090/login.html 技术栈&#xff1a;后端&#xff1a;javaspringbootmy…

利用HTML5的一个重要特性 —— DeviceOrientation来实现手机网站上的摇一摇功能

介绍之前做两个声明&#xff1a; 以下代码可以直接运行&#xff0c;当然你别忘了引用jQuery才行。 <script> // DeviceOrientation将底层的方向传感器和运动传感器进行了高级封装&#xff0c;提供了DOM事件的支持。 // 这个特性包括两个事件&#xff1a; // 1、deviceOri…

项目简介-NodeJS+MongoDB实现简单网站

项目简介-NodeJSMongoDB实现简单网站 主要是参考视频学习。视频地址&#xff1a; http://www.imooc.com/learn/75 一、项目要求 要求在云计算平台上采用脚本语言NoSQL数据库实现一个简单的在线应用系统。 以小组实验报告的形式提交。 二、项目简介 2122网站&#xff0c;是…

基于SSM实现的简易员工管理系统(基于阿里云的网站上线篇)

2017-9-9 16:49更新&#xff1a; 好的&#xff0c;现在看来不备案是彻底玩不了了&#xff0c;想看看界面的&#xff0c;可以通过ip访问&#xff0c;IP好像暂时还没有封&#xff0c;不知道还能活多久&#xff0c;哎~&#xff08;101.132.76.93&#xff09; 2017-9-8 23:23更新&…

基于SSM实现的简易员工管理系统(基于阿里云的网站上线篇)

2017-9-9 16:49更新&#xff1a; 好的&#xff0c;现在看来不备案是彻底玩不了了&#xff0c;想看看界面的&#xff0c;可以通过ip访问&#xff0c;IP好像暂时还没有封&#xff0c;不知道还能活多久&#xff0c;哎~&#xff08;101.132.76.93&#xff09; 2017-9-8 23:23更新&…

Ubuntu安装docker,使用docker安装awvs,并测试网站输出测试报告

Ubuntu安装docker&#xff0c;使用docker安装awvs&#xff0c;并测试网站输出测试报告 1.Ubuntu安装docker ​ 在Ubuntu中按CtrlAltT进入终端命令&#xff0c;实际安装参考Ubuntu Docker 安装 | 菜鸟教程 (runoob.com) 我是用下面的命令&#xff0c;然后系统提醒缺啥&#x…

自助建站工具 搭建出来的网站真的适合SEO吗?

最近有一个做SEO优化朋友问笔者&#xff0c;为什么自助建站做出来的网站排名很难做上去。我的第一个反应是&#xff0c;不会吧&#xff0c;用自助建站做出来的网站做SEO&#xff0c;这要是能做上去排名&#xff0c;那才叫奇怪呢。但是呢&#xff0c;又不能和朋友这样直接说&…

网站建设精选案例之网站商城

网站商城的模板虽然差不多&#xff0c;但是同一个模板设计出来的东西有所不同&#xff0c;效果也不一样。 案例一&#xff1a;乐城网购&#xff08;www.lemalling.com&#xff09; 乐城网购商城是依托中国硅谷北京中关村的科技、电子、服务优势而创立的新一代专业电子商务消费…

IT行业网站建设的四种模板特色

“网站建设”在各行各业已不是一个陌生的名词。无论是金融、物流、服务行业&#xff0c;还是食 品、化工行业&#xff0c;大家都想通过建立网站&#xff0c;来促进企业的发展。但是&#xff0c;网站建设并不是一项容易的工程&#xff0c;不是直接复制那些做得比较好的网站就可以…

凡科建站之音乐古筝网站建设案例分析

凡科网为秦筝音乐工作室建立的网站&#xff0c;古筝有柔美&#xff0c;清雅的特点&#xff0c;网站风格也完全依照企业的特点去建设的&#xff0c;进入网站伴随而来的是清脆的音乐&#xff0c;让人似乎置身于竹林&#xff0c;享受着此时此刻的宁静。 网站首页配上富有中秋韵味…

数码产品网站建设都有哪些特色?

今天要介绍的是数码产品网站该如何设计。之前我也说过了&#xff0c;不同行业网站突出的重点也有所不一样&#xff0c;正如现在所说的B2B,B2C,C2C等类型。B2B的网站主要是展现企业的文化、荣誉&#xff0c;树立企业品牌&#xff0c;这是企业网站宣传目的。而B2C和C2C重点在与产…

服装行业的网站建设的特点

互联网的兴起对不同行业都产生了巨大的影响。各种大型综合门户网站悄然而至&#xff0c;使得这类型的网站出现饱和情况&#xff0c;专业性网站成为时代发展的必然趋势。服装行业的网站也越来越多&#xff0c;网站也各有特色的服务&#xff0c;各有风格。 通过对几家服装网站分…

网站建设解决方案之海华科技

网站建设案例&#xff1a;海华科技 所属产品业务&#xff1a;提供多媒体会议室 网站关键词&#xff1a;北京海华建达科技发展有限公司、专业显示系统服务商、海华科技 凡科网受海华科技之托&#xff0c;为北京海华建达科技发展有限公司建设网站&#xff0c;也就是海华科技网…

网页设计金酸梅奖:世界上最烂的网站

【PConline 欣赏】想把网页设计好很难&#xff0c;但是想把网页设计的差容易了很多&#xff0c;方法也很多。配色使用不当&#xff0c;字体选用不搭调都能降低页面的可读性&#xff0c;这对网站来说是很致命的。有的设计缺陷是用户无法及时找到信息&#xff0c;而有的缺陷是视觉…

自助建站之页面边框样式设置

自助建站秉承着会打字就会建站的理念&#xff0c;提供非常简单、易用的自助建站系统&#xff0c;让个人或者企业能够快速、方便的建设出自己想要的网站&#xff0c;就算是零基础的建站者&#xff0c;也能在几分钟内建设出一个网站&#xff0c;那么在使用凡科自助建站系统的时候…