纯粹依照自己的想法仿照b站的弹幕写的一个demo,不知道正确的姿势怎么样的。

demo下载地址

首先。一条弹幕就是一个textview

public abstract class Danmu extends TextView{
private Context context;
private int position;//弹幕的位置,在屏幕哪一行 public Danmu(Context context) {
super(context);
this.context=context;
setSingleLine();
} public int getPosition() {
return position;
} public void setPosition(int position) {
this.position = position;
} public abstract void send(); }

将弹幕放在一个相对布局容器中

 <RelativeLayout
android:id="@+id/danmuContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3" />

当字数非常多时,会放不下全部文字,所以手动设置了容器的宽度

容器设置足够大就好

ViewGroup.LayoutParams lp=container.getLayoutParams();
lp.width=DensityUtils.sp2px(this,15)*100;
container.setLayoutParams(lp);

弹幕分为好几种这里做了普通的从右到左的。逆向的。还有在顶部和底部的

普通弹幕由两个TranslateAnimation完毕,第一个是当弹幕移动后空出足够多空间时通知其它弹幕能够跟在它后面,第二个动画完毕接下来的移出屏幕

public class NormalDanmu extends Danmu {
private Animation animation0,animation1;
private int fx0,tx0,fx1,tx1;
private int duration0,duration1;
private OnAnimationEndListener onAnimationEndListener; public interface OnAnimationEndListener
{
public void clearPosition();//第一个动画结束,将当前行设置为能够发送弹幕
public void animationEnd();//弹幕全然移出屏幕
} public NormalDanmu(Context context,int fx,int tx)
{
super(context);
this.fx0=fx;
this.tx0=Math.abs(fx)-Math.abs(tx)-100;//第一个动画结束位置,当尾部空出100像素时就能够通知其它弹幕跟上了
this.fx1=tx0;
this.tx1=tx; duration0=2000*(Math.abs(tx0-fx0))/DensityUtils.getScreenW(context);
duration1=2000*(Math.abs(tx1-fx1))/DensityUtils.getScreenW(context); initAnimation();
} private void initAnimation()
{
animation0=new TranslateAnimation(fx0,tx0,0,0);
animation1=new TranslateAnimation(fx1,tx1,0,0);
animation0.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) { } @Override
public void onAnimationEnd(Animation animation) { clearAnimation();
startAnimation(animation1);
if (onAnimationEndListener!=null)
{
onAnimationEndListener.clearPosition();
}
} @Override
public void onAnimationRepeat(Animation animation) { }
}); animation0.setFillAfter(true);
animation0.setDuration(duration0);
animation0.setInterpolator(new AccelerateInterpolator()); animation1.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) { } @Override
public void onAnimationEnd(Animation animation) { if(onAnimationEndListener!=null)
{
onAnimationEndListener.animationEnd();
} } @Override
public void onAnimationRepeat(Animation animation) { }
}); animation1.setFillAfter(true);
animation1.setDuration(duration1);
animation1.setInterpolator(new DecelerateInterpolator());
} public void setOnAnimationEndListener(OnAnimationEndListener onAnimationEndListener)
{
this.onAnimationEndListener=onAnimationEndListener;
} @Override
public void send() {
startAnimation(animation0);
}
}

然后发送弹幕 final NormalDanmu danmu=new NormalDanmu(this,sWidth,(int) -paint.measureText(str));

swidth表示屏幕宽度。paint.measureText(str)是textview宽度,表示从最右端移动到左边全然移出屏幕

lp.addRule(RelativeLayout.ALIGN_PARENT_TOP);

lp.topMargin=i*danmuHeight;

danmuHeight是一个textview的高度,这里设置放在容器的第i行

private void setDanmu()
{
String ss="按是按时按是android.os.BinderProx按是";
int ll=ss.length()*DensityUtils.sp2px(this,15);
int ran= new Random().nextInt(ss.length());
String str=ss.substring(ran);
final NormalDanmu danmu=new NormalDanmu(this,sWidth,(int) -paint.measureText(str));
danmu.setTextSize(15);
danmu.setText(str);
danmu.setOnAnimationEndListener(new NormalDanmu.OnAnimationEndListener() {
@Override
public void clearPosition() { sendPosition.put(danmu.getPosition(), false);
} @Override
public void animationEnd() { container.removeView(danmu);
} }); for(int i=0;i<count;i++)
{
if(sendPosition.get(i)==false)
{
danmu.setPosition(i);
RelativeLayout.LayoutParams lp=new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, danmuHeight);
lp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
lp.topMargin=i*danmuHeight;
danmu.setGravity(Gravity.CENTER);
container.addView(danmu, lp); danmu.send(); sendPosition.put(i,true);
break;
} }
}



逆向弹幕就是和普通弹幕移动方向不同其它全然一样



顶部和底部的弹幕主要就是显示几秒后再消失即可了比較简单

public class TopDanmu extends Danmu {
private OnDisappearListener onDisappearListener;
private int duration;
private Handler handler=new Handler()
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what==1)
{
if(onDisappearListener!=null)
{
onDisappearListener.disappear();
}
}
}
}; public TopDanmu(Context context,int duration) {
super(context);
this.duration=duration;
} public interface OnDisappearListener
{
public void disappear();
}
@Override
public void send() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(duration);
handler.sendEmptyMessage(1); } catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
} public void setOnDisappearListener(OnDisappearListener onDisappearListener )
{
this.onDisappearListener=onDisappearListener;
}
}

发送顶部弹幕

顶部弹幕要水平居中,这里的容器设置的宽度超过的屏幕大小。所以要手动计算弹幕的水平位置

int margin= (int) ((sWidth-paint.measureText(danmu.getText().toString()))/2);



private void setTopDanmu()
{
String ss="按是按时按是android.os.BinderProx按是"; int ran= new Random().nextInt(ss.length());
String str=ss.substring(ran);
int ll=str.length()*DensityUtils.sp2px(this, 15);
final TopDanmu danmu=new TopDanmu(this,2000);
danmu.setTextSize(15);
danmu.setText(str);
danmu.setTextColor(Color.GREEN);
danmu.setOnDisappearListener(new TopDanmu.OnDisappearListener() {
@Override
public void disappear() {
container.removeView(danmu);
topSendPosition.put(danmu.getPosition(), false);
}
}); for(int i=0;i<count;i++)
{
if(topSendPosition.get(i)==false)
{
danmu.setPosition(i);
RelativeLayout.LayoutParams lp=new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, danmuHeight);
lp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
int margin= (int) ((sWidth-paint.measureText(danmu.getText().toString()))/2);
lp.topMargin=i*danmuHeight;
lp.leftMargin=margin;
danmu.setGravity(Gravity.CENTER);
container.addView(danmu, lp); danmu.send(); topSendPosition.put(i,true);
break;
} }
}









android 弹幕评论效果的更多相关文章

  1. Android弹幕编程设计实现的解决方案(一)

     Android弹幕编程设计实现的解决方案(一) 在现在的一些视频类网站.视频类直播网站,比如A站和B站,当视频在播放的时候,会在屏幕上出现一些滚动的字幕,这些字幕是UGC,通常是用户的评论,称之 ...

  2. 【Android源代码下载】收集整理android界面UI效果源码

    在Android开发中,Android界面UI效果设计一直都是很多童鞋关注的问题,今天给大家分享下大神收集整理的多个android界面UI效果,都是源码,都是干货,贡献给各位网友! 话不多说,直接上效 ...

  3. Android ViewPager 动画效果

    找到个不错的开源项目:https://github.com/jfeinstein10/JazzyViewPager Android ViewPager 动画效果   

  4. android 弹幕效果demo

    记得之前有位朋友在我的公众号里问过我,像直播的那种弹幕功能该如何实现?如今直播行业确实是非常火爆啊,大大小小的公司都要涉足一下直播的领域,用斗鱼的话来讲,现在就是千播之战.而弹幕则无疑是直播功能当中最 ...

  5. Android弹幕功能实现,模仿斗鱼直播的弹幕效果

    转载出处:http://blog.csdn.net/sinyu890807/article/details/51933728 本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭霖 即 ...

  6. Android 弹幕效果开发案例

    概述 现在有个很流行的效果就是弹幕效果,满屏幕的文字从右到左飘来飘去.看的眼花缭乱,看起来还蛮cool的 现在就是来实现这一的一个效果,大部分的都是从右向左移动漂移,本文的效果中也支持从左向右的漂移移 ...

  7. Android ListView各种效果实现总结,持续更新...

    一.ListView圆角:重写ListView的onInterceptTouchEvent方法,通过pointToPosition(x,y)方法判断当前点击位置所对应的项,有三种情况:分别是第一项.最 ...

  8. Android 遮罩层效果

    (用别人的代码进行分析) 不知道在开发中有没有经常使用到这种效果,所谓的遮罩层就是给一张图片不是我们想要的形状,这个时候我们就可以使用遮罩效果把这个图片变成我们想要的形状,一般使用最多就是圆形的效果, ...

  9. Android登录等待效果

    上一篇为大家分享了关于AsyncTask的使用,本篇结合AsyncTask为大家介绍一个我们经常看到的一个效果,就是当我们点击登录后,会弹出一个请等待的小窗体,这个效果是如何实现的呢?本篇我就带大家简 ...

随机推荐

  1. Java 异常的捕获与处理详解 (一)

    一,异常的产生(Exception) 异常是程序之中导致程序中断的一种指令流,异常一旦出现并且没有进行合理处理的话,那么程序就会中断执行. An exception is a flow of inst ...

  2. 【ICM Technex 2018 and Codeforces Round #463 (Div. 1 + Div. 2, combined) C】 Permutation Cycle

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] p[i] = p[p[i]]一直进行下去 在1..n的排列下肯定会回到原位置的. 即最后会形成若干个环. g[i]显然等于那个环的大 ...

  3. ECNUOJ 2150 完美的拯救

    完美的拯救 Time Limit:1000MS Memory Limit:65536KBTotal Submit:147 Accepted:50 Description  一只可怜的蚂蚁被万恶的魔术师 ...

  4. POJ 2241 The Tower of Babylon

    The Tower of Babylon Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on PKU. Or ...

  5. 洛谷 P1443 马的遍历

    P1443 马的遍历 题目描述 有一个n*m的棋盘(1<n,m<=400),在某个点上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步 输入输出格式 输入格式: 一行四个数据,棋盘 ...

  6. hdu 1024 最大m子段和

    注:摘的老师写的 最大m子段和问题 以-1 4 -2 3 -2 3为例最大子段和是:6最大2子段和是:4+(3-2+3)=8所以,最大子段和和最大m子段和不一样,不能用比如先求一个最大子段和,从序列中 ...

  7. 网络载入数据和解析JSON格式数据案例之空气质量监測应用

    一.创建一个新的项目 activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res ...

  8. [Android随笔]内存泄漏以及内存溢出

    名词解释 内存泄漏:memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏危害能够忽略,但内存泄漏堆积后果非常严重,不管多少内存,迟早会被占光. 内存溢出:out of ...

  9. jquery<=======>js实现方法

    http://haorooms.com/post/js_shixian_jquery

  10. OPENCV(2) —— Basic Structures(一)

    DataType A primitive OpenCV data type is one of unsigned char, bool,signed char, unsigned short, sig ...