zoukankan      html  css  js  c++  java
  • Android:简单的弹幕效果达到

    首先,效果图。分类似至360检测到的骚扰电话页面:


    布局非常easy,上面是一个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; } } } }

    2.平移动画生成工具:

    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;
        }
    }
    ScreenUtils是用来获取屏幕宽高、dp与px之间互转的工具类。

    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;
        }
    }
    4.TanmuBean是一个实体类

    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;
        }
    }

    ==========

    源代码下载:http://download.csdn.net/detail/books1958/9005279 






    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    ASP.NET CORE 使用Consul实现服务治理与健康检查(2)——源码篇
    ASP.NET CORE 使用Consul实现服务治理与健康检查(1)——概念篇
    Asp.Net Core 单元测试正确姿势
    如何通过 Docker 部署 Logstash 同步 Mysql 数据库数据到 ElasticSearch
    Asp.Net Core2.2 源码阅读系列——控制台日志源码解析
    使用VS Code 开发.NET CORE 程序指南
    .NetCore下ES查询驱动 PlainElastic .Net 升级官方驱动 Elasticsearch .Net
    重新认识 async/await 语法糖
    EF添加
    EF修改部分字段
  • 原文地址:https://www.cnblogs.com/yxwkf/p/4852550.html
Copyright © 2011-2022 走看看