Android之弹幕(一)带头像


写直播时组长要求要带头像的弹幕,于是写了一个demo,在弹幕的基础上添加了一个布局,直接上效果吧



先看下xml里面的弹幕布局

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="50dp"
    android:orientation="horizontal"
    android:background="#0ff">

    <com.see.tmlayout.CircleImageView
        android:id="@+id/barrage_item_img"
        android:layout_width="50dp"
        android:layout_height="match_parent"
        android:src="@drawable/qq"/>

    <TextView
        android:id="@+id/barrage_item_tv"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:text="测试弹幕"
        android:gravity="center"
        android:textColor="#fff"/>
</LinearLayout>
CircleImageView是圆形图片,网上一搜就有。

这是Tm布局没什么好说的
public class Barrage implements Serializable {
    private String barrageInfo;
    private String barrageUrl;

    public Barrage(String barrageInfo, String barrageUrl) {
        this.barrageInfo = barrageInfo;
        this.barrageUrl = barrageUrl;
    }

    public String getBarrageInfo() {
        return barrageInfo;
    }

    public void setBarrageInfo(String barrageInfo) {
        this.barrageInfo = barrageInfo;
    }

    public String getBarrageUrl() {
        return barrageUrl;
    }

    public void setBarrageUrl(String barrageUrl) {
        this.barrageUrl = barrageUrl;
    }
}

接下来就是Tm的自定义
public class BarrageView extends FrameLayout {
    private static ArrayList<Barrage> mData = new ArrayList<>(); //数据
    private int nowIndex = 0; //mData的下标
    private Bitmap nowBitmap; //当前图片
    private int width;                //控件宽
    private int height;               //控件高
    private float scale;              //像素密度
    private FrameLayout frameLayout;
    private FrameLayout.LayoutParams tvParams;

    static boolean IS_START = false;    //判断是否开始

    long allTime; //视频总时长
    long startTime; //开始时间

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Barrage barrage = (Barrage) msg.getData().getSerializable("barrage");
            final LinearLayout layout = (LinearLayout) LayoutInflater.from(getContext()).inflate(R.layout.barrage_itme, null);
            layout.setLayoutParams(tvParams);
            //随机获得Y值
            layout.setY(getRandomY());
            layout.setX(width + layout.getWidth());

            //设置文字
            TextView textView = (TextView) layout.findViewById(R.id.barrage_item_tv);
            textView.setText(barrage.getBarrageInfo());

            //设置图片
            CircleImageView imageView = (CircleImageView) layout.findViewById(R.id.barrage_item_img);
            if (nowBitmap != null) {
                imageView.setImageBitmap(nowBitmap);
            }

            frameLayout.addView(layout);

            final ObjectAnimator anim = ObjectAnimator.ofFloat(layout, "translationX", -width);
            anim.setDuration(10000);

            //释放资源
            anim.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {
                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    anim.cancel();
                    layout.clearAnimation();
                    frameLayout.removeView(layout);
                }

                @Override
                public void onAnimationCancel(Animator animation) {
                }

                @Override
                public void onAnimationRepeat(Animator animation) {

                }
            });
            anim.start();
        }
    };

    /**
     * 使用httprulconnection通过发送网络请求path获得bitmap
     *
     * @param path
     * @return
     */
    public static Bitmap getBitmapFromUrl(String path) {
        try {
            //获得url
            URL url = new URL(path);
            //打开 httpRulConnection 获得实例
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            //设置超时时间
            conn.setConnectTimeout(5000);
            //设置Get
            conn.setRequestMethod("GET");
            //连接成功
            if (conn.getResponseCode() == 200) {
                //获得输入流
                InputStream inputStream = conn.getInputStream();
                //得到bitmap
                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                if (bitmap == null) {
                }
                //返回
                return bitmap;
            }
            //错误信息处理
        } catch (Exception e) { //打印错误信息
            e.printStackTrace();
        }
        return null;
    }

    int lastY;//上一次出现的Y值

    /**
     * 获得随机的Y轴的值
     *
     * @return
     */
    private float getRandomY() {
        int tempY;
        int rY;
        int result = 0;
        // height * 2 / 4 - 25
        //首先随机选择一条道路
        int nowY = (int) (Math.random() * 3);
        switch (nowY) {
            case 0:
                nowY = avoidTheSameY(nowY, lastY);
                //第一条
                tempY = height / 4 - 25;
                rY = (int) (Math.random() * height / 4);
                if (rY >= height / 8) {
                    result = tempY + rY;
                } else {
                    result = tempY - rY + 50;
                }
                lastY = nowY;
                break;
            case 1:
                nowY = avoidTheSameY(nowY, lastY);
                //第二条
                tempY = height / 2 - 25;
                rY = (int) (Math.random() * height / 4);
                if (rY >= height / 8) {
                    result = tempY + rY;
                } else {
                    result = tempY - rY;
                }
                lastY = nowY;
                break;
            case 2:
                nowY = avoidTheSameY(nowY, lastY);
                //第三条
                tempY = height * 3 / 4 - 25;
                rY = (int) (Math.random() * height / 4);
                if (rY >= height / 8) {
                    result = tempY + rY - 50;
                } else {
                    result = tempY - rY;
                }
                lastY = nowY;
                break;
        }
        return result;
    }

    /**
     * 避免Y重合的方法
     *
     * @param lastY
     * @return
     */
    private int avoidTheSameY(int nowY, int lastY) {
        if (nowY == lastY) {
            nowY++;
        }
        if (nowY == 4) {
            nowY = 0;
        }
        return nowY;
    }


    public BarrageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        width = getWidth(); //宽度
        height = getHeight();   //高度
        init();
    }

    private void init() {
        setTime(600000);    //设置初始时长,改完记得删

        startTime = System.currentTimeMillis();

        scale = this.getResources().getDisplayMetrics().density;
        //获得自身实例
        frameLayout = (FrameLayout) findViewById(R.id.barrageView);
        tvParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, 50);

        if (IS_START) {
            //开始动画线程
            startBarrageView();
            IS_START = false;
        }
    }

    public void startBarrageView() {
        //开启线程发送弹幕
        new Thread() {
            @Override
            public void run() {

                while ((System.currentTimeMillis() - startTime < allTime)
                        && (nowIndex <= mData.size() - 1)) {
                    try {
                        nowBitmap = getBitmapFromUrl(mData.get(nowIndex).getBarrageUrl());
                        Message message = new Message();
                        Bundle bundle = new Bundle();
                        bundle.putSerializable("barrage", mData.get(nowIndex));
                        nowIndex++;
                        message.setData(bundle);
                        handler.sendMessage(message);
                        Thread.sleep((long) (Math.random() * 3000) + 1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                return;
            }
        }.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    //设置数据
    public void setSentenceList(ArrayList<Barrage> data) {
        mData = data;
        IS_START = true;
    }

    //获得视频总时长
    public void setTime(long time) {
        allTime = time;
    }
}

之后在声明View传入数据就可以了
下面是Activity里的XML和代码应用

<RelativeLayout
    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"
    tools:context="com.see.tmlayout.MainActivity">

    <com.see.tmlayout.BarrageView
        android:id="@+id/barrageView"
        android:layout_width="match_parent"
        android:layout_height="400dp"/>

</RelativeLayout>

public class MainActivity extends AppCompatActivity {
    private BarrageView mBarrageView;
    private ArrayList<Barrage> data;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        data = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            data.add(new Barrage("测试弹幕" + i
                    , "http://pic.818today.com/imgsy/image/2016/0215/6359114592207963687677523.jpg"));
        }
        mBarrageView = (BarrageView) findViewById(R.id.barrageView);
        mBarrageView.setSentenceList(data);
    }
}
解析的数据添加到data集合里就大功告成了!

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值