Android 简易弹幕效果实现

来源:互联网 发布:网络直播的发展趋势 编辑:程序博客网 时间:2024/05/16 04:55


Android:简易弹幕效果实现



首先上效果图,类似于360检测到骚扰电话页面:


布局很简单,上面是一个RelativeLayout,下面一个Button.

功能:

(1)弹幕生成后自动从右侧往左侧滚动(TranslateAnimation),弹幕消失后立刻被移除。

(2)弹幕位置随机出现,并且不重复(防止文字重叠)。

(3)字体大小在一定范围内随机改变,字体颜色也可以设置。

(4)自定义先减速,后加速的Interpolator,弹幕加速进入、减速停留、然后加速出去。

1.Activity代码:

[java] view plaincopy
  1. /** 
  2.  * 简易弹幕效果实现 
  3.  * Created by admin on 15-6-4. 
  4.  */  
  5. public class MainActivity extends ActionBarActivity {  
  6.     private MyHandler handler;  
  7.   
  8.     //弹幕内容  
  9.     private TanmuBean tanmuBean;  
  10.     //放置弹幕内容的父组件  
  11.     private RelativeLayout containerVG;  
  12.   
  13.     //父组件的高度  
  14.     private int validHeightSpace;  
  15.   
  16.     @Override  
  17.     protected void onCreate(Bundle savedInstanceState) {  
  18.         super.onCreate(savedInstanceState);  
  19.         setContentView(R.layout.activity_main);  
  20.   
  21.         containerVG = (RelativeLayout) findViewById(R.id.tanmu_container);  
  22.         tanmuBean = new TanmuBean();  
  23.         tanmuBean.setItems(new String[]{"测试一下""弹幕这东西真不好做啊""总是出现各种问题~~""也不知道都是为什么?麻烦!""哪位大神可以帮帮我啊?""I need your help.",  
  24.                 "测试一下""弹幕这东西真不好做啊""总是出现各种问题~~""也不知道都是为什么?麻烦!""哪位大神可以帮帮我啊?""I need your help.",  
  25.                 "测试一下""弹幕这东西真不好做啊""总是出现各种问题~~""也不知道都是为什么?麻烦!""哪位大神可以帮帮我啊?""I need your help."});  
  26.   
  27.         handler = new MyHandler(this);  
  28.   
  29.         //开始弹幕  
  30.         View startTanmuView = findViewById(R.id.startTanmu);  
  31.         startTanmuView.setOnClickListener(new View.OnClickListener() {  
  32.             @Override  
  33.             public void onClick(View v) {  
  34.                 if (containerVG.getChildCount() > 0) {  
  35.                     return;  
  36.                 }  
  37.   
  38.                 existMarginValues.clear();  
  39.                 new Thread(new CreateTanmuThread()).start();  
  40.             }  
  41.         });  
  42.     }  
  43.   
  44.     //每2s自动添加一条弹幕  
  45.     private class CreateTanmuThread implements Runnable {  
  46.         @Override  
  47.         public void run() {  
  48.             int N = tanmuBean.getItems().length;  
  49.             for (int i = 0; i < N; i++) {  
  50.                 handler.obtainMessage(1, i, 0).sendToTarget();  
  51.                 SystemClock.sleep(2000);  
  52.             }  
  53.         }  
  54.     }  
  55.   
  56.     //需要在主线城中添加组件  
  57.     private static class MyHandler extends Handler {  
  58.         private WeakReference<MainActivity> ref;  
  59.   
  60.         MyHandler(MainActivity ac) {  
  61.             ref = new WeakReference<>(ac);  
  62.         }  
  63.   
  64.         @Override  
  65.         public void handleMessage(Message msg) {  
  66.             super.handleMessage(msg);  
  67.   
  68.             if (msg.what == 1) {  
  69.                 MainActivity ac = ref.get();  
  70.                 if (ac != null && ac.tanmuBean != null) {  
  71.                     int index = msg.arg1;  
  72.                     String content = ac.tanmuBean.getItems()[index];  
  73.                     float textSize = (float) (ac.tanmuBean.getMinTextSize() * (1 + Math.random() * ac.tanmuBean.getRange()));  
  74.                     int textColor = ac.tanmuBean.getColor();  
  75.   
  76.                     ac.showTanmu(content, textSize, textColor);  
  77.                 }  
  78.             }  
  79.         }  
  80.     }  
  81.   
  82.     private void showTanmu(String content, float textSize, int textColor) {  
  83.         final TextView textView = new TextView(this);  
  84.   
  85.         textView.setTextSize(textSize);  
  86.         textView.setText(content);  
  87. //        textView.setSingleLine();  
  88.         textView.setTextColor(textColor);  
  89.   
  90.         int leftMargin = containerVG.getRight() - containerVG.getLeft() - containerVG.getPaddingLeft();  
  91.         //计算本条弹幕的topMargin(随机值,但是与屏幕中已有的不重复)  
  92.         int verticalMargin = getRandomTopMargin();  
  93.         textView.setTag(verticalMargin);  
  94.   
  95.         LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
  96.         params.addRule(RelativeLayout.ALIGN_PARENT_TOP);  
  97.         params.topMargin = verticalMargin;  
  98.   
  99.         textView.setLayoutParams(params);  
  100.         Animation anim = AnimationHelper.createTranslateAnim(this, leftMargin, -ScreenUtils.getScreenW(this));  
  101.         anim.setAnimationListener(new Animation.AnimationListener() {  
  102.             @Override  
  103.             public void onAnimationStart(Animation animation) {  
  104.   
  105.             }  
  106.   
  107.             @Override  
  108.             public void onAnimationEnd(Animation animation) {  
  109.                 //移除该组件  
  110.                 containerVG.removeView(textView);  
  111.                 //移除占位  
  112.                 int verticalMargin = (int) textView.getTag();  
  113.                 existMarginValues.remove(verticalMargin);  
  114.             }  
  115.   
  116.             @Override  
  117.             public void onAnimationRepeat(Animation animation) {  
  118.   
  119.             }  
  120.         });  
  121.         textView.startAnimation(anim);  
  122.   
  123.         containerVG.addView(textView);  
  124.     }  
  125.   
  126.     //记录当前仍在显示状态的弹幕的位置(避免重复)  
  127.     private Set<Integer> existMarginValues = new HashSet<>();  
  128.     private int linesCount;  
  129.   
  130.     private int getRandomTopMargin() {  
  131.         //计算用于弹幕显示的空间高度  
  132.         if (validHeightSpace == 0) {  
  133.             validHeightSpace = containerVG.getBottom() - containerVG.getTop()  
  134.                     - containerVG.getPaddingTop() - containerVG.getPaddingBottom();  
  135.         }  
  136.   
  137.         //计算可用的行数  
  138.         if (linesCount == 0) {  
  139.             linesCount = validHeightSpace / ScreenUtils.dp2px(this, tanmuBean.getMinTextSize() * (1 + tanmuBean.getRange()));  
  140.             if (linesCount == 0) {  
  141.                 throw new RuntimeException("Not enough space to show text.");  
  142.             }  
  143.         }  
  144.   
  145.         //检查重叠  
  146.         while (true) {  
  147.             int randomIndex = (int) (Math.random() * linesCount);  
  148.             int marginValue = randomIndex * (validHeightSpace / linesCount);  
  149.   
  150.             if (!existMarginValues.contains(marginValue)) {  
  151.                 existMarginValues.add(marginValue);  
  152.                 return marginValue;  
  153.             }  
  154.         }  
  155.     }  
  156. }  
2.平移动画生成工具:

[java] view plaincopy
  1. public class AnimationHelper {  
  2.     /** 
  3.      * 创建平移动画 
  4.      */  
  5.     public static Animation createTranslateAnim(Context context, int fromX, int toX) {  
  6.         TranslateAnimation tlAnim = new TranslateAnimation(fromX, toX, 00);  
  7.         //自动计算时间  
  8.         long duration = (long) (Math.abs(toX - fromX) * 1.0f / ScreenUtils.getScreenW(context) * 4000);  
  9.         tlAnim.setDuration(duration);  
  10.         tlAnim.setInterpolator(new DecelerateAccelerateInterpolator());  
  11.         tlAnim.setFillAfter(true);  
  12.   
  13.         return tlAnim;  
  14.     }  
  15. }  
ScreenUtils是用来获取屏幕宽高、dp与px之间互转的工具类。

3.自定义的Interpolator,其实只有一行代码

[java] view plaincopy
  1. public class DecelerateAccelerateInterpolator implements Interpolator {  
  2.   
  3.     //input从0~1,返回值也从0~1.返回值的曲线表征速度加减趋势  
  4.     @Override  
  5.     public float getInterpolation(float input) {  
  6.         return (float) (Math.tan((input * 2 - 1) / 4 * Math.PI)) / 2.0f + 0.5f;  
  7.     }  
  8. }  
4.TanmuBean是一个实体类

[java] view plaincopy
  1. public class TanmuBean {  
  2.     private String[] items;  
  3.     private int color;  
  4.     private int minTextSize;  
  5.     private float range;  
  6.   
  7.     public TanmuBean() {  
  8.         //init default value  
  9.         color = Color.parseColor("#eeeeee");  
  10.         minTextSize = 16;  
  11.         range = 0.5f;  
  12.     }  
  13.   
  14.     public String[] getItems() {  
  15.         return items;  
  16.     }  
  17.   
  18.     public void setItems(String[] items) {  
  19.         this.items = items;  
  20.     }  
  21.   
  22.     public int getColor() {  
  23.         return color;  
  24.     }  
  25.   
  26.     public void setColor(int color) {  
  27.         this.color = color;  
  28.     }  
  29.   
  30.     /** 
  31.      * min textSize, in dp. 
  32.      */  
  33.     public int getMinTextSize() {  
  34.         return minTextSize;  
  35.     }  
  36.   
  37.     public void setMinTextSize(int minTextSize) {  
  38.         this.minTextSize = minTextSize;  
  39.     }  
  40.   
  41.     public float getRange() {  
  42.         return range;  
  43.     }  
  44.   
  45.     public void setRange(float range) {  
  46.         this.range = range;  
  47.     }  
  48. }  

0 0
原创粉丝点击