实例解析如何在Android应用中实现弹幕动画效果
在b站或者其他视频网站看视频时,常常会打开弹幕效果,边看节目边看大家的吐槽。弹幕看起来很有意思,今天我们就来实现一个简单的弹幕效果。
从直观上,弹幕效果就是在一个viewgroup上增加一些view,然后让这些view移动起来。所以,整体的实现思路大概是这样的:
1、定义一个relativelayout,在里面动态添加textview。
2、这些textview的字体大小、颜色、移动速度、初始位置都是随机的。
3、将textview添加到relativelayout的右边缘,每隔一段时间添加一个。
4、对每个textview做平移动画,使得textview从右向左移动。
5、当textview从左边移动出屏幕,将textview从relativelayout中移除。
有了思路下面就来看具体的代码。
首先定义barrageitem,用来存储每一个弹幕项的相关信息,包括字体内容、字体大小颜色、移动速度、垂直方向的位置、字体占据的宽度等。
public class barrageitem { public textview textview; public int textcolor; public string text; public int textsize; public int movespeed;//移动速度 public int verticalpos;//垂直方向显示的位置 public int textmeasuredwidth;//字体显示占据的宽度 }
然后定义barrageview,由于弹幕的字体颜色大小和移动速度都是随机的,需要定义最大最小值来限定它们的范围,然后通过产生随机数来设置它们在这个范围内的值。另外还需要定义弹幕的文本内容,这里是直接写死的一些固定值。
private context mcontext; private barragehandler mhandler = new barragehandler(); private random random = new random(system.currenttimemillis()); private static final long barrage_gap_min_duration = 1000;//两个弹幕的最小间隔时间 private static final long barrage_gap_max_duration = 2000;//两个弹幕的最大间隔时间 private int maxspeed = 10000;//速度,ms private int minspeed = 5000;//速度,ms private int maxsize = 30;//文字大小,dp private int minsize = 15;//文字大小,dp private int totalheight = 0; private int lineheight = 0;//每一行弹幕的高度 private int totalline = 0;//弹幕的行数 private string[] itemtext = {"是否需要帮忙", "what are you 弄啥来", "哈哈哈哈哈哈哈", "抢占沙发。。。。。。", "************", "是否需要帮忙","我不会轻易的狗带", "嘿嘿", "这是我见过的最长长长长长长长长长长长的评论"}; private int textcount; // private list<barrageitem> itemlist = new arraylist<barrageitem>(); public barrageview(context context) { this(context, null); } public barrageview(context context, attributeset attrs) { this(context, attrs, 0); } public barrageview(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); mcontext = context; init(); }
如果弹幕显示的垂直位置是随机的,就会出现垂直方向上弹幕重叠的情况,所以需要根据高度对垂直方向按照弹幕高度的最大值等分,然后让弹幕在这些指定的垂直位置随机分布。这个值在onwindowfocuschanged里计算,因为在这个方法中通过view的getmeasuredheight()得到的高度不为空。
@override public void onwindowfocuschanged(boolean haswindowfocus) { super.onwindowfocuschanged(haswindowfocus); totalheight = getmeasuredheight(); lineheight = getlineheight(); totalline = totalheight / lineheight; } 通过handler的sendemptymessagedelayed每隔随机的时间产生一个弹幕项。下面的代码设置弹幕项的属性。 class barragehandler extends handler { @override public void handlemessage(message msg) { super.handlemessage(msg); generateitem(); //每个弹幕产生的间隔时间随机 int duration = (int) ((barrage_gap_max_duration - barrage_gap_min_duration) * math.random()); this.sendemptymessagedelayed(0, duration); } } private void generateitem() { barrageitem item = new barrageitem(); string tx = itemtext[(int) (math.random() * textcount)]; int sz = (int) (minsize + (maxsize - minsize) * math.random()); item.textview = new textview(mcontext); item.textview.settext(tx); item.textview.settextsize(sz); item.textview.settextcolor(color.rgb(random.nextint(256), random.nextint(256), random.nextint(256))); item.textmeasuredwidth = (int) gettextwidth(item, tx, sz); item.movespeed = (int) (minspeed + (maxspeed - minspeed) * math.random()); if (totalline == 0) { totalheight = getmeasuredheight(); lineheight = getlineheight(); totalline = totalheight / lineheight; } item.verticalpos = random.nextint(totalline) * lineheight; showbarrageitem(item); }
将每一个弹幕项添加到视图上,并给view添加一个translateanimation动画,当动画结束时,将view从视图上移除。
private void showbarrageitem(final barrageitem item) { int leftmargin = this.getright() - this.getleft() - this.getpaddingleft(); layoutparams params = new layoutparams(layoutparams.wrap_content, layoutparams.wrap_content); params.addrule(relativelayout.align_parent_top); params.topmargin = item.verticalpos; this.addview(item.textview, params); animation anim = generatetranslateanim(item, leftmargin); anim.setanimationlistener(new animation.animationlistener() { @override public void onanimationstart(animation animation) { } @override public void onanimationend(animation animation) { item.textview.clearanimation(); barrageview.this.removeview(item.textview); } @override public void onanimationrepeat(animation animation) { } }); item.textview.startanimation(anim); } private translateanimation generatetranslateanim(barrageitem item, int leftmargin) { translateanimation anim = new translateanimation(leftmargin, -item.textmeasuredwidth, 0, 0); anim.setduration(item.movespeed); anim.setinterpolator(new acceleratedecelerateinterpolator()); anim.setfillafter(true); return anim; }
这样就完成了弹幕的功能,实现原理并不复杂。可以根据具体的需求来增加更多的控制,如控制每一行弹幕不重复,控制弹幕移动的interpolator产生不同的滑动效果等等。