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="發(fā)送"/>
</LinearLayout>
</LinearLayout>
2.主類(lèi): 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);//先獲取部分?jǐn)?shù)據(jù)
for (int i = 0; i < array.length; i++) {
mList.add(array[i]);
}
mDanMuView.setData(mList);//向彈幕框添加數(shù)據(jù)
mDanMuView.startDanmu();//開(kāi)始彈幕
}
//初始化
private void initView() {
mText = (EditText) findViewById(R.id.text);
mDanMuView = (DanMuView) findViewById(R.id.danmu);
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {//發(fā)送按鈕
@Override
public void onClick(View v) {
//發(fā)送評(píng)論
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);//線(xiàn)程池
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);
}
/**
* 添加數(shù)據(jù)到彈幕中
*
* @param list
*/
public void setData(List<String> list) {
this.mList = list;
}
/**
* 用戶(hù)發(fā)送評(píng)論彈幕
*
* @param data
*/
public void insertDanmu(String data) {
showDanmu(data);//顯示彈幕
mList.add(data);//將彈幕信息添加到集合的第一位
startDanmu();//開(kāi)始彈幕
}
/**
* 開(kāi)始彈幕
*/
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);//評(píng)論內(nèi)容長(zhǎng)度限制
danmu_img.setImageResource(R.drawable.deta_shoucz);
danmu_text.setText(str);//設(shè)置彈幕
danmu_container.setBackgroundResource(R.drawable.textview_bg);//設(shè)置背景
int leftMargin = mContainerVG.getRight() - mContainerVG.getLeft() - mContainerVG.getPaddingLeft();
//計(jì)算本條彈幕的topMargin(隨機(jī)值,但是與屏幕中已有的不重復(fù))
int verticalMargin = getRandomTopMargin();
LayoutParams params = new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);//設(shè)置節(jié)點(diǎn)屬性,上邊緣
params.topMargin = verticalMargin;
danmu_container.setLayoutParams(params);
//動(dòng)畫(huà)
Animation anim = new AnimationHelper().createTranslateAnim(mContext, leftMargin, -getScreenWidth((Activity) mContext));
//動(dòng)畫(huà)監(jiān)聽(tīng)
anim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
//動(dòng)畫(huà)結(jié)束時(shí)移除控件
mContainerVG.removeView(danmu_container);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
danmu_container.startAnimation(anim);//開(kāi)始動(dòng)畫(huà)
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();
}
/**
* 評(píng)論的長(zhǎng)度限制
* @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;
}
//動(dòng)畫(huà)
public class AnimationHelper{
public AnimationHelper() {
}
//fromX 開(kāi)始的位置 ,toX結(jié)束的位置
public Animation createTranslateAnim(Context context, int fromX, int toX){
TranslateAnimation translateAnimation = new TranslateAnimation(fromX, toX, 0, 0);
int width = getScreenWidth((Activity)context);//獲取屏幕的寬度
//自動(dòng)計(jì)算時(shí)間
long duration = (long) (Math.abs(toX - fromX) * 1.0f / width * 6000);
translateAnimation.setDuration(duration);//動(dòng)畫(huà)時(shí)間
// translateAnimation.setInterpolator(new DecelerateAccelerateInterpolator());//動(dòng)畫(huà)速率
translateAnimation.setFillAfter(true);//終止時(shí)停留最后一幀
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.