欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

很棒的Android弹幕效果实例

程序员文章站 2024-02-29 14:29:16
很多项目需要用到弹幕效果,尤其是在播放视频的时候需要一起显示别人发的弹幕,也包括自己的发的。 今天就试着写了一下这个效果。  思路就是将从右往左的动画效果,字...

很多项目需要用到弹幕效果,尤其是在播放视频的时候需要一起显示别人发的弹幕,也包括自己的发的。

今天就试着写了一下这个效果。

 思路就是将从右往左的动画效果,字体内容,字体大小,弹幕平移速度等属性一起与textview封装成barrageitem,并将控制效果与barrageitem绑定在barrageview进行显示。思路还是比较简单的。这里没有考虑到带有表情的弹幕,我会持续更新的。

 先看效果:

 很棒的Android弹幕效果实例                  

 项目目录结构:

 很棒的Android弹幕效果实例                        

 接下来定义barrageitem.class : 这个类就将textview与从右往左的动画效果,字体内容,字体大小,弹幕平移速度等属性绑定。              

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,由于弹幕的字体颜色大小和移动速度都是随机的,需要定义最大最小值来限定它们的范围,然后通过产生随机数来设置它们在这个范围内的值。另外还需要定义弹幕的文本内容,这里是直接写死的一些固定值。

barrageview.class:

public class barrageview extends relativelayout { 
 
  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; 
 
  // 速度,ms 
  private int maxspeed = 12000; 
 
  // 速度,ms 
  private int minspeed = 8000; 
 
  // 文字最大值 
  private int maxsize = 50; 
 
  // 文字最小值 
  private int minsize = 10; 
 
  private int totalheight = 0; 
 
  private int lineheight = 0;// 每一行弹幕的高度 
 
  private int totalline = 0;// 弹幕的行数 
 
  private string[] itemtext = { "他们都说蔡睿智很帅,但他总觉得自己很丑", 
      "他们都说蔡睿智是男神,但他只觉得自己是男生", "蔡睿智不是男神,蔡睿智是男生", "蔡睿智貌似是gay", "蔡睿智是弯的", 
      "蔡睿智是弯的,还好现在掰回来了", "他承受了他这个年纪不该有的机智与帅气,他好累", 
      "我恨自己的颜值,我觉得自己的才华才是吸引别人的地方", "他为什么对妹子不感兴趣呢?为什么?", "他为什么不想谈恋爱","他不会去爱别人,同时也不希望别人去爱他,他已经习惯一个人了", 
      "他的心里是否住着一个苍老的小孩", "他的世界一直就是他和他的影子,直到遇到她", "她引导他走出了自己的世界,改变他的很多看法", 
      "他渐渐的发现自己已经离不开他,他选择不再去压抑自己", "因为他已经不是那个无能为力的年纪","她经常说他 高冷,现在越来越觉得他恨闷骚","开始他一直与她保持朋友距离,但他发现自己根本作不到"}; 
  private int textcount; 
 
  public barrageview(context context, attributeset attrs, int defstyleattr) { 
    super(context, attrs, defstyleattr); 
    mcontext = context; 
    _init(); 
  } 
 
  public barrageview(context context, attributeset attrs) { 
    this(context, null, 0); 
 
  } 
 
  public barrageview(context context) { 
    this(context, null); 
 
  } 
 
  private void _init() { 
    textcount = itemtext.length; 
    int duration = (int) ((barrage_gap_max_duration - barrage_gap_min_duration) * math 
        .random()); 
    mhandler.sendemptymessagedelayed(0, duration); 
  } 
 
  @override 
  public void onwindowfocuschanged(boolean haswindowfocus) { 
    super.onwindowfocuschanged(haswindowfocus); 
    totalheight = getmeasuredheight(); 
    lineheight = getlineheight(); 
    totalline = totalheight / lineheight; 
  } 
 
  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); 
  } 
 
  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 arg0) { 
 
      } 
 
      @override 
      public void onanimationrepeat(animation arg0) { 
         
      } 
 
      @override 
      public void onanimationend(animation arg0) { 
        item.textview.clearanimation(); 
        barrageview.this.removeview(item.textview); 
      } 
    }); 
    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; 
  } 
 
  /** 
   * 计算textview中字符串的长度 
   * 
   * @param item 
   * @param text 
   *      要计算的字符串 
   * @param size 
   *      字体大小 
   * @return textview中字符串的长度 
   */ 
  public float gettextwidth(barrageitem item, string text, float size) { 
    rect bounds = new rect(); 
    textpaint paint; 
    paint = item.textview.getpaint(); 
    paint.gettextbounds(text, 0, text.length(), bounds); 
    return bounds.width(); 
  } 
 
  /** 
   * 获得每一行弹幕的最大高度 
   */ 
  private int getlineheight() { 
    barrageitem item = new barrageitem(); 
    string tx = itemtext[0]; 
    item.textview = new textview(mcontext); 
    item.textview.settext(tx); 
    item.textview.settextsize(maxsize); 
 
    rect bounds = new rect(); 
    textpaint paint; 
    paint = item.textview.getpaint(); 
    paint.gettextbounds(tx, 0, tx.length(), bounds); 
    return bounds.height(); 
  } 
 
  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); 
    } 
  } 
 
} 

如果弹幕显示的垂直位置是随机的,就会出现垂直方向上弹幕重叠的情况,所以需要根据高度对垂直方向按照弹幕高度的最大值等分,然后让弹幕在这些指定的垂直位置随机分布。这个值在onwindowfocuschanged里计算,因为在这个方法中通过view的getmeasuredheight()得到的高度不为空。             

 mainactivity.class:

<span style="font-size:18px;">public class mainactivity extends activity { 
 
  @override 
  protected void oncreate(bundle savedinstancestate) { 
    super.oncreate(savedinstancestate); 
    setcontentview(r.layout.activity_main); 
  } 
}</span> 

以上就是弹幕的源码,其实我觉得这里少了自己发送弹幕的功能,我会在以后的更新上去的,共勉。