1.布局文件: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>
2.主类: 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);
}
});
}
}
3.自定义弹幕显示框控件: 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;
}
}
}
4.弹幕容器布局: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>
5.弹幕子控件布局: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.