首先上效果图,类似于360检测到骚扰电话页面:
布局很简单,上面是一个RelativeLayout,下面一个Button.
功能:
(1)弹幕生成后自动从右侧往左侧滚动(TranslateAnimation),弹幕消失后立刻被移除。
(2)弹幕位置随机出现,并且不重复(防止文字重叠)。
(3)字体大小在一定范围内随机改变,字体颜色也可以设置。
(4)自定义先减速,后加速的Interpolator,弹幕加速进入、减速停留、然后加速出去。
1.Activity代码:
- /**
- * 简易弹幕效果实现
- * Created by admin on 15-6-4.
- */
- public class MainActivity extends ActionBarActivity {
- private MyHandler handler;
- //弹幕内容
- private TanmuBean tanmuBean;
- //放置弹幕内容的父组件
- private RelativeLayout containerVG;
- //父组件的高度
- private int validHeightSpace;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- containerVG = (RelativeLayout) findViewById(R.id.tanmu_container);
- tanmuBean = new TanmuBean();
- tanmuBean.setItems(new String[]{"测试一下", "弹幕这东西真不好做啊", "总是出现各种问题~~", "也不知道都是为什么?麻烦!", "哪位大神可以帮帮我啊?", "I need your help.",
- "测试一下", "弹幕这东西真不好做啊", "总是出现各种问题~~", "也不知道都是为什么?麻烦!", "哪位大神可以帮帮我啊?", "I need your help.",
- "测试一下", "弹幕这东西真不好做啊", "总是出现各种问题~~", "也不知道都是为什么?麻烦!", "哪位大神可以帮帮我啊?", "I need your help."});
- handler = new MyHandler(this);
- //开始弹幕
- View startTanmuView = findViewById(R.id.startTanmu);
- startTanmuView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (containerVG.getChildCount() > 0) {
- return;
- }
- existMarginValues.clear();
- new Thread(new CreateTanmuThread()).start();
- }
- });
- }
- //每2s自动添加一条弹幕
- private class CreateTanmuThread implements Runnable {
- @Override
- public void run() {
- int N = tanmuBean.getItems().length;
- for (int i = 0; i < N; i++) {
- handler.obtainMessage(1, i, 0).sendToTarget();
- SystemClock.sleep(2000);
- }
- }
- }
- //需要在主线城中添加组件
- private static class MyHandler extends Handler {
- private WeakReference<MainActivity> ref;
- MyHandler(MainActivity ac) {
- ref = new WeakReference<>(ac);
- }
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- if (msg.what == 1) {
- MainActivity ac = ref.get();
- if (ac != null && ac.tanmuBean != null) {
- int index = msg.arg1;
- String content = ac.tanmuBean.getItems()[index];
- float textSize = (float) (ac.tanmuBean.getMinTextSize() * (1 + Math.random() * ac.tanmuBean.getRange()));
- int textColor = ac.tanmuBean.getColor();
- ac.showTanmu(content, textSize, textColor);
- }
- }
- }
- }
- private void showTanmu(String content, float textSize, int textColor) {
- final TextView textView = new TextView(this);
- textView.setTextSize(textSize);
- textView.setText(content);
- // textView.setSingleLine();
- textView.setTextColor(textColor);
- int leftMargin = containerVG.getRight() - containerVG.getLeft() - containerVG.getPaddingLeft();
- //计算本条弹幕的topMargin(随机值,但是与屏幕中已有的不重复)
- int verticalMargin = getRandomTopMargin();
- textView.setTag(verticalMargin);
- LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
- params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
- params.topMargin = verticalMargin;
- textView.setLayoutParams(params);
- Animation anim = AnimationHelper.createTranslateAnim(this, leftMargin, -ScreenUtils.getScreenW(this));
- anim.setAnimationListener(new Animation.AnimationListener() {
- @Override
- public void onAnimationStart(Animation animation) {
- }
- @Override
- public void onAnimationEnd(Animation animation) {
- //移除该组件
- containerVG.removeView(textView);
- //移除占位
- int verticalMargin = (int) textView.getTag();
- existMarginValues.remove(verticalMargin);
- }
- @Override
- public void onAnimationRepeat(Animation animation) {
- }
- });
- textView.startAnimation(anim);
- containerVG.addView(textView);
- }
- //记录当前仍在显示状态的弹幕的位置(避免重复)
- private Set<Integer> existMarginValues = new HashSet<>();
- private int linesCount;
- private int getRandomTopMargin() {
- //计算用于弹幕显示的空间高度
- if (validHeightSpace == 0) {
- validHeightSpace = containerVG.getBottom() - containerVG.getTop()
- - containerVG.getPaddingTop() - containerVG.getPaddingBottom();
- }
- //计算可用的行数
- if (linesCount == 0) {
- linesCount = validHeightSpace / ScreenUtils.dp2px(this, tanmuBean.getMinTextSize() * (1 + tanmuBean.getRange()));
- if (linesCount == 0) {
- throw new RuntimeException("Not enough space to show text.");
- }
- }
- //检查重叠
- while (true) {
- int randomIndex = (int) (Math.random() * linesCount);
- int marginValue = randomIndex * (validHeightSpace / linesCount);
- if (!existMarginValues.contains(marginValue)) {
- existMarginValues.add(marginValue);
- return marginValue;
- }
- }
- }
- }
- public class AnimationHelper {
- /**
- * 创建平移动画
- */
- public static Animation createTranslateAnim(Context context, int fromX, int toX) {
- TranslateAnimation tlAnim = new TranslateAnimation(fromX, toX, 0, 0);
- //自动计算时间
- long duration = (long) (Math.abs(toX - fromX) * 1.0f / ScreenUtils.getScreenW(context) * 4000);
- tlAnim.setDuration(duration);
- tlAnim.setInterpolator(new DecelerateAccelerateInterpolator());
- tlAnim.setFillAfter(true);
- return tlAnim;
- }
- }
3.自定义的Interpolator,其实只有一行代码
- public class DecelerateAccelerateInterpolator implements Interpolator {
- //input从0~1,返回值也从0~1.返回值的曲线表征速度加减趋势
- @Override
- public float getInterpolation(float input) {
- return (float) (Math.tan((input * 2 - 1) / 4 * Math.PI)) / 2.0f + 0.5f;
- }
- }
- public class TanmuBean {
- private String[] items;
- private int color;
- private int minTextSize;
- private float range;
- public TanmuBean() {
- //init default value
- color = Color.parseColor("#eeeeee");
- minTextSize = 16;
- range = 0.5f;
- }
- public String[] getItems() {
- return items;
- }
- public void setItems(String[] items) {
- this.items = items;
- }
- public int getColor() {
- return color;
- }
- public void setColor(int color) {
- this.color = color;
- }
- /**
- * min textSize, in dp.
- */
- public int getMinTextSize() {
- return minTextSize;
- }
- public void setMinTextSize(int minTextSize) {
- this.minTextSize = minTextSize;
- }
- public float getRange() {
- return range;
- }
- public void setRange(float range) {
- this.range = range;
- }
- }