Android的简易弹幕

-----------------------------------------------------------------------------------------------------------------------------

一段时间没写Android了,有时间必须来敲一敲Android的代码才行,不然很快就忘光了.

发现AS的快捷键很多都忘记了.                              敲了一份弹幕的Demo

-----------------------------------------------------------------------------------------------------------------------------

  • 布局文件:activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.skg.danmudemo.MainActivity">
    <!--自定义弹幕显示框控件-->
    <com.skg.danmudemo.DanMuView
        android:id="@+id/danmu"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/text"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_weight="1"/>

        <Button
            android:id="@+id/btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="发送"/>

    </LinearLayout>
</LinearLayout>

  • 主类: MainActivity

/**
 * @author ClamLaw
 * @time 2016/11/26  
 * @desc MainActivity
 */
public class MainActivity extends AppCompatActivity {

    private EditText mText;
    private List<String> mList = new ArrayList<>();
    private DanMuView mDanMuView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();//初始化
        initData();

    }

    private void initData() {
        String[] array = getResources().getStringArray(R.array.danmuList);//先获取部分数据
        for (int i = 0; i < array.length; i++) {
            mList.add(array[i]);
        }
        mDanMuView.setData(mList);//向弹幕框添加数据
        mDanMuView.startDanmu();//开始弹幕
    }

    //初始化
    private void initView() {
        mText = (EditText) findViewById(R.id.text);
        mDanMuView = (DanMuView) findViewById(R.id.danmu);
        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {//发送按钮
            @Override
            public void onClick(View v) {
                //发送评论
                String str = mText.getText().toString();
                mDanMuView.insertDanmu(str);
            }
        });
    }
}

  •  自定义弹幕显示框控件: DanMuView

/**
 * @author ClamLaw
 * @time 2016/11/26  19:01
 * @desc 自定义弹幕的view
 */
public class DanMuView extends RelativeLayout {
    private Context mContext;
    private View view;
    private RelativeLayout mContainerVG;
    private List<String> mList;
    //父组件的高度
    private int validHeightSpace;
    private Set existMarginValues = new HashSet<>();
    private int lastMarginValue;
    ExecutorService executorService = Executors.newFixedThreadPool(1);//线程池

    Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 1:
                    int index = msg.arg1;
                    String data = mList.get(index);
                    showDanmu(data);
                    break;
            }
        }
    };

    public DanMuView(Context context) {
        super(context);
    }

    public DanMuView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
        view = LayoutInflater.from(context).inflate(R.layout.danmu_view, null, false);
        mContainerVG = (RelativeLayout) view.findViewById(R.id.danmu);
        mContainerVG.setBackgroundDrawable(null);
        addView(view);
    }

    /**
     * 添加数据到弹幕中
     *
     * @param list
     */
    public void setData(List<String> list) {
        this.mList = list;
    }

    /**
     * 用户发送评论弹幕
     *
     * @param data
     */
    public void insertDanmu(String data) {
        showDanmu(data);//显示弹幕
        mList.add(data);//将弹幕信息添加到集合的第一位
        startDanmu();//开始弹幕
    }

    /**
     * 开始弹幕
     */
    public void startDanmu() {
       existMarginValues.clear();
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                for (int i =0 ;i<Integer.MAX_VALUE; i++){
                    int size = mList.size();
                    if (size==0){
                        break;
                    }
                    mHandler.obtainMessage(1,i%size,0).sendToTarget();
                    SystemClock.sleep(1000);
                }
            }
        });
    }

    /**
     * 显示弹幕
     */
    public void showDanmu(String data) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.item_danmu, null, false);
        final RelativeLayout danmu_container = (RelativeLayout) view.findViewById(R.id.danmu_container);
        TextView danmu_text = (TextView) view.findViewById(R.id.danmu_text);
        ImageView danmu_img = (ImageView)view.findViewById(R.id.danmu_img);
        String str = clipLongTextByChineseCount(data, 12);//评论内容长度限制
        danmu_img.setImageResource(R.drawable.deta_shoucz);
        danmu_text.setText(str);//设置弹幕
        danmu_container.setBackgroundResource(R.drawable.textview_bg);//设置背景

        int leftMargin = mContainerVG.getRight() - mContainerVG.getLeft() - mContainerVG.getPaddingLeft();
        //计算本条弹幕的topMargin(随机值,但是与屏幕中已有的不重复)
        int verticalMargin = getRandomTopMargin();

        LayoutParams params = new LayoutParams(
            LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        params.addRule(RelativeLayout.ALIGN_PARENT_TOP);//设置节点属性,上边缘
        params.topMargin = verticalMargin;

        danmu_container.setLayoutParams(params);

        //动画
        Animation anim = new AnimationHelper().createTranslateAnim(mContext, leftMargin, -getScreenWidth((Activity) mContext));
        //动画监听
        anim.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                //动画结束时移除控件
                mContainerVG.removeView(danmu_container);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });

        danmu_container.startAnimation(anim);//开始动画
        mContainerVG.addView(danmu_container);
    }

    private int getRandomTopMargin() {
        if (validHeightSpace == 0) {
            validHeightSpace = mContainerVG.getBottom() - mContainerVG.getTop()
                - mContainerVG.getPaddingBottom() - mContainerVG.getTop();
        }
        if (existMarginValues.size() == 3) {
            existMarginValues.clear();
            while (true) {
                int randomIndex = (int) (Math.random() * 5);
                int marginValue = randomIndex * (validHeightSpace / 5);
                if (lastMarginValue != marginValue) {
                    existMarginValues.add(marginValue);
                    return marginValue;
                }
            }
        } else {
            //检查重叠
            while (true) {
                int randomIndex = (int) (Math.random() * 5);
                int marginValue = randomIndex * (validHeightSpace / 5);

                if (!existMarginValues.contains(marginValue)) {
                    existMarginValues.add(marginValue);
                    if (existMarginValues.size() == 3) {
                        lastMarginValue = marginValue;
                    }
                    return marginValue;
                }
            }
        }
    }

    /**
     * 获取屏幕的宽度
     * @param context
     * @return
     */
    private int getScreenWidth(Context context) {
        WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        return manager.getDefaultDisplay().getWidth();
    }

    /**
     * 评论的长度限制
     * @param str
     * @param count
     * @return
     */
    public static String clipLongTextByChineseCount(String str, int count) {
        if (str != null) {
            final String encoding = "GBK";
            try {
                byte[] b = str.getBytes(encoding);
                if (b.length >= (count + 1) * 2) {
                    int end = count * 2;
                    String result = new String(b, 0, end, encoding);
                    if (str.indexOf(result) == -1) {
                        return new String(b, 0, end - 1, encoding) + "...";
                    }
                    return result + "...";
                }
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
        return str;
    }

    //动画
    public class AnimationHelper{

        public AnimationHelper() {
        }
        //fromX 开始的位置 ,toX结束的位置
        public Animation createTranslateAnim(Context context, int fromX, int toX){
            TranslateAnimation translateAnimation = new TranslateAnimation(fromX, toX, 0, 0);
            int width = getScreenWidth((Activity)context);//获取屏幕的宽度
            //自动计算时间
            long duration = (long) (Math.abs(toX - fromX) * 1.0f / width * 6000);
            translateAnimation.setDuration(duration);//动画时间
           // translateAnimation.setInterpolator(new DecelerateAccelerateInterpolator());//动画速率
            translateAnimation.setFillAfter(true);//终止时停留最后一帧
            return translateAnimation;
        }
    }



    public class DecelerateAccelerateInterpolator implements Interpolator {
        @Override
        public float getInterpolation(float input) {
            return (float) (Math.tan((input * 2 - 1) / 4 * Math.PI)) / 2.0f + 0.5f;
        }
    }
}

  • 弹幕容器布局:danmu_view.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <RelativeLayout
        android:id="@+id/danmu"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

  • 弹幕子控件布局:item_danmu.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:id="@+id/danmu_container"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    <ImageView
        android:id="@+id/danmu_img"
        android:layout_width="25dp"
        android:layout_height="25dp"
        android:layout_marginLeft="1px"
        android:layout_marginTop="1px"/>
    <TextView
        android:id="@+id/danmu_text"
        android:textColor="@android:color/white"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:singleLine="true"
        android:layout_marginLeft="25dp"
        android:text="123123"
        android:textSize="20dp"/>
</RelativeLayout>

本Demo的源码下载链接  DanMuDemo.

-----------------------------------------------------------------------------------------------------------------------------

结束!

如有错误或不足之处,请大家指出,谢谢!

-----------------------------------------------------------------------------------------------------------------------------

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值