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

Android实现自定义的弹幕效果

程序员文章站 2024-03-31 19:16:58
一、效果图 先来看看效果图吧~~ 二、实现原理方案 1、自定义viewgroup-xcdanmuview,继承relativelayout来实现,当然也可以继承其...

一、效果图

先来看看效果图吧~~

Android实现自定义的弹幕效果

二、实现原理方案

1、自定义viewgroup-xcdanmuview,继承relativelayout来实现,当然也可以继承其他三大布局类哈

2、初始化若干个textview(弹幕的item view,这里以textview 为例,当然也可以其他了~),然后通过addview添加到自定义view

3、通过addview添加到xcdanmuview中,位置在坐标,为了实现 从屏幕外移动进来的效果

我们还需要修改添加进来textview的位置,以从右向左移动方向来说,addview后必须将该textview的位置设置到右边的屏幕外

这样我们采用的方法,是在onlayout()方法中对childview进行layout重新布局设置位置

4、随机冲左侧或右侧出来弹幕itemview,移动采用属性动画来实现平移,从屏幕的一端移动到另一端,当动画结束后,就将

child从xcdanmuviewremove掉。并重新new 一个弹幕itemview ,并addviewxcdanmuview中,并开始动画移动

5、本自定义弹幕view支持从左到右和从右到左两个方向,支持自定义设置屏幕弹幕最多显示个数。

 

三、自定义弹幕效果xcdanmuview的具体实现

1、初始化需要用到的数据变量

private int mwidth;
  private int mscreenwidth;
  private list<view> mchildlist;
  private boolean misworking = false;
  private context mcontext;
  private int mmaxshownum = 15;
  private int mrownum = 4;
  private int[] mspeeds = {
      3000,4000,5000,6000
  };
  private int mdelayduration = 500;
  private int[] mbgresids = {
      r.drawable.bg_danmu0,
      r.drawable.bg_danmu1,
      r.drawable.bg_danmu2,
      r.drawable.bg_danmu3
  };
  private int[] mrowpos = {
      150,140,160,150
  };
  private random mrandom;
  private string[] mstrcontents;
  public static enum xcdirection{
    from_right_to_left,
    form_left_to_right
  }
  public enum xcaction{
    show,hide
  }
  private xcdirection mdirection = xcdirection.from_right_to_left;
  private void init() {
  mscreenwidth = getscreenwidth();
  mchildlist = new arraylist<>();
  mrandom = new random();
}

2、初始化若干个弹幕item view

public void initdanmuitemviews(string[] strcontents){
    mstrcontents = strcontents;
    for(int i = 0; i < mmaxshownum; i ++){
      int index = mrandom.nextint(100) % strcontents.length;
      createdanmuview(i,strcontents[index],false);
    }
  }

3、创建弹幕item view 并addview到xcdanmuview中

public void createdanmuview(int index,string content,boolean reset){
    final textview textview = new textview(mcontext);
    textview.settextcolor(color.white);
    int r = mrandom.nextint(100) % mrownum;
    textview.setbackgroundresource(mbgresids[r]);
    textview.settext(content +"_"+ (index+1));
    relativelayout.layoutparams lp = new layoutparams(layoutparams.wrap_content,
        relativelayout.layoutparams.wrap_content);
    int row = mrandom.nextint(100) % mrownum;
    while(row == lastrow){
      row = mrandom.nextint(100)% mrownum;
    }
    int pos = mrandom.nextint(100)% mrownum;
    lp.topmargin = row * mrowpos[pos];
    lastrow = row;
    textview.setlayoutparams(lp);
    textview.setpadding(40, 2, 40, 2);
    this.addview(textview);
    if(reset){
      mchildlist.set(index,textview);
    }else{
      mchildlist.add(index,textview);
    }
    textview.setclickable(true);
    textview.setonclicklistener(new onclicklistener() {
      @override
      public void onclick(view view) {
        toast toast = toast.maketext(mcontext, textview.gettext(), toast.length_short);
        toast.setgravity(gravity.top,0,50);
        toast.show();
      }
    });
  }

4、重新设置childview的初始位置到屏幕之外

@override
  protected void onlayout(boolean changed, int l, int t, int r, int b) {
    super.onlayout(changed, l, t, r, b);
    int childcount = this.getchildcount();
    for(int i=0;i<childcount;i++){
      view view = getchildat(i);
      relativelayout.layoutparams lp = (layoutparams) view.getlayoutparams();
      if(lp.leftmargin <= 0){
        if(mdirection == xcdirection.form_left_to_right){
          view.layout(-view.getmeasuredwidth(), lp.topmargin,
              0,lp.topmargin + view.getmeasuredheight());
        }else{
          view.layout(mscreenwidth,lp.topmargin,mscreenwidth+view.getmeasuredwidth(),
              lp.topmargin+view.getmeasuredheight());
        }

      }else{
        continue;
      }
    }
  }

5、弹幕item view的移动效果

private handler mhandler = new handler() {
    @override
    public void handlemessage(final message msg) {
      super.handlemessage(msg);
      final int pos = msg.what;
      viewpropertyanimator animator;
      if(mdirection == xcdirection.from_right_to_left){
        animator = mchildlist.get(msg.what).animate()
            .translationxby(-(mscreenwidth + mchildlist.get(msg.what).getwidth()));
      }else{
        animator = mchildlist.get(msg.what).animate()
            .translationxby(mscreenwidth + mchildlist.get(msg.what).getwidth());
      }

      random random = new random(system.currenttimemillis());
      int index = random.nextint(100) % mspeeds.length;
      animator.setduration(mspeeds[index]);
      animator.setinterpolator(new linearinterpolator());
      animator.setlistener(new animator.animatorlistener() {
        @override
        public void onanimationstart(animator animator) {

        }

        @override
        public void onanimationend(animator animator) {
          xcdanmuview.this.removeview(mchildlist.get(pos));
          int index = mrandom.nextint(100) % mstrcontents.length;
          createdanmuview(pos, mstrcontents[index], true);
          mhandler.sendemptymessagedelayed(pos, mdelayduration);
          log.v("czm", "size=" + mchildlist.size());
        }

        @override
        public void onanimationcancel(animator animator) {

        }

        @override
        public void onanimationrepeat(animator animator) {

        }
      });
      animator.start();
    }
  };

 6、开启弹幕效果和关闭弹幕效果以及对于的动画效果

boolean isfirst = true;
  public void start(){
    switchanimation(xcaction.show);
    if(isfirst){
      for(int i =0;i< mchildlist.size();i++){
        mhandler.sendemptymessagedelayed(i,i * mdelayduration);
      }
      isfirst = false;
    }

    misworking = true;
  }
  public void hide(){
    switchanimation(xcaction.hide);
    misworking =false;
  }
  public void stop(){
    this.setvisibility(view.gone);
    for(int i =0;i< mchildlist.size();i++){
      mchildlist.get(i).clearanimation();
      mhandler.removemessages(i);
    }
    misworking =false;
  }
private void switchanimation(final xcaction action){
    alphaanimation animation;
    if(action == xcaction.hide){
      animation = new alphaanimation(1.0f,0.0f);
      animation.setduration(400);
    }else{
      animation = new alphaanimation(0.0f,1.0f);
      animation.setduration(1000);
    }
    xcdanmuview.this.startanimation(animation);
    animation.setanimationlistener(new animation.animationlistener() {
      @override
      public void onanimationstart(animation animation) {

      }
      @override
      public void onanimationend(animation animation) {
        if(action == xcaction.hide){
          xcdanmuview.this.setvisibility(view.gone);
        }else{
          xcdanmuview.this.setvisibility(view.visible);
        }
      }
      @override
      public void onanimationrepeat(animation animation) {

      }
    });
  }

四、如何使用该自定义侧滑view控件

使用该自定义view非常简单,控件默认效果从右向左,如果需要修改方向为从左到右,只需设置下方向即可

public class mainactivity extends activity {

  private xcdanmuview mdanmuview;
  private list<view> mviewlist;
  private string[] mstritems = {
      "搜狗","百度",
      "腾讯","360",
      "阿里巴巴","搜狐",
      "网易","新浪",
      "搜狗-上网从搜狗开始","百度一下,你就知道",
      "必应搜索-有求必应","好搜-用好搜,特顺手",
      "android-谷歌","ios-苹果",
      "windows-微软","linux"
  };
  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_main);
    initdanmuview();
    initlistener();
  }

  private void initlistener() {
    findviewbyid(r.id.btn).setonclicklistener(new view.onclicklistener() {
      @override
      public void onclick(view view) {
        if (mdanmuview.isworking()) {
          mdanmuview.hide();
          ((button) view).settext("开启弹幕");
        } else {
          mdanmuview.start();
          ((button) view).settext("关闭弹幕");
        }
      }
    });
  }

  private void initdanmuview() {
    mdanmuview = (xcdanmuview)findviewbyid(r.id.danmu);
    mdanmuview.initdanmuitemviews(mstritems);
  }

}

五、总结

以上就是在android中实现自定义弹幕效果的全部内容个,希望本文的内容对大家开发android的时候能有所帮助。如果有疑问可以留言交流。