写直播时组长要求要带头像的弹幕,于是写了一个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集合里就大功告成了!