import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class DanMuView extends View implements Runnable{
private static final String TAG = "DanMuView";
//用来绘制弹幕的画笔, 通过它来设置弹幕的字体大小, 颜色等等
private TextPaint mTextPaint;
//创建一个List来保存所添加的弹幕TextItem
List<TextItem> mTextItems = new ArrayList<TextItem>();
Random random = new Random();
public DanMuView(Context context) {
this(context, null);
}
public DanMuView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setColor(Color.RED);
mTextPaint.setTextSize(30);
//开启自己
new Thread(this). start();
}
public void addTextItemRandom(String content) {
if (content != null) {
TextItem item = null;
for (TextItem textItem : mTextItems) {
if (canReuse(textItem, mDanmuViewWidth, mDanmuViewHeight)) {
item = textItem;
}
}
if (item == null) {
item = new TextItem(content);
//只有新创建的才会添加到List中, 其他的说明可以复用了
mTextItems.add(item);
} else {
item.setmContent(content);
}
float x = 10, y = 100;
if (mDanmuViewWidth > 0 && mDanmuViewHeight > 0) {
x = random.nextFloat() * mDanmuViewWidth;
y = random.nextFloat() * mDanmuViewHeight + mTextPaint.getTextSize();
} else {
x = 500;
y = random.nextFloat() * 100 + mTextPaint.getTextSize();
}
//设置TextItem的x,y坐标
item.setmLocX(x);
item.setmLocY(y);
//设置TextItem的颜色为随即的
int r = random.nextInt(255);
int g = random.nextInt(255);
int b = random.nextInt(255);
item.setmColor(Color.rgb(r, g, b));
//设置TextItem向左移动的速度也为随机的
item.setmSteps(random.nextFloat() * 80);
//设置TextItem的宽度
item.setmTextWidth(mTextPaint.measureText(content));
//最后讲创建出的TextItem添加到List中, 然后在onDraw方法中遍历,并画出来
//mTextItems.add(item);
Log.e(TAG, "addTextItemRandom: mTextItems.size() is " + mTextItems.size());
}
}
/**
* 判断是否可以复用
* @param item
* @param w
* @param h
* @return
*/
private static final boolean canReuse(TextItem item, float w, float h) {
boolean ret = true;
if (item != null && w > 0 && h > 0) {
float iX = item.getmLocX();
float iY = item.getmLocY();
if (iX < w) {
//没有超过最右侧
float textWidth = item.getmTextWidth();
if (iX > -textWidth) {
ret = false;
}
}
}
return ret;
}
/**
* 在onDraw方法中进行绘制弹幕的文本信息
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
Log.e(TAG, "onDraw: ");
//调用Canvas的drawText方法来进行绘制一个Text文本信息
if (mDanmuViewWidth > 0 && mDanmuViewHeight > 0) {
//canvas.drawText("Hello World", mTextX, mTextY, mTextPaint);
for (TextItem item : mTextItems) {
// TODO 此处做优化
/**String content = item.getmContent();
float x = item.getmLocX();
float y = item.getmLocY();
int color = item.getmColor();
float textWidth = item.getmTextWidth();
mTextPaint.setColor(color);
if (y > 0 && y < mDanmuViewHeight
&& x > -textWidth && x < mDanmuViewWidth){
canvas.drawText(content, x, y, mTextPaint);
}*/
if (!canReuse(item, mDanmuViewWidth, mDanmuViewHeight)) {
String content = item.getmContent();
float x = item.getmLocX();
float y = item.getmLocY();
int color = item.getmColor();
mTextPaint.setColor(color);
canvas.drawText(content, x, y, mTextPaint);
}
}
}
}
/**
* 当CanvasView的宽高发生改变时调用, 也就是xml文件中的DanMuView已经显示在屏幕上
* @param w
* @param h
* @param oldw
* @param oldh
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mDanmuViewWidth = w;
mDanmuViewHeight = h;
}
private boolean mRunning;
//用来判断子线程是否需要继续执行, 当Activity不是前端运行状态时, 需中断线程
private boolean mPaused;
//当前CanvasView自己的宽度
private float mDanmuViewWidth;
//当前CanvasView自己的高度
private float mDanmuViewHeight;
public void onResume() {
mPaused = false;
}
public void onPause () {
mPaused = true;
}
public void exitLoop() {
mRunning = false;
}
/**
* 自身实现Runnable接口,
* 注意一定是子线程中更新状态, UI线程的onDraw方法只负责绘制即可
*/
@Override
public void run() {
mRunning = true;
try {
while (mRunning) {
if (mDanmuViewWidth > 0 && mDanmuViewHeight > 0 && !mPaused) {
//有尺寸,才绘制
//TODO 更新每一个TextItem的位置
//TODO 考虑都移出去,并且没有再添加的问题
boolean needPaint = false;
for (TextItem item : mTextItems) {
item.moveLeft();
if (!canReuse(item, mDanmuViewWidth, mDanmuViewHeight)) {
needPaint = true;
}
}
if (needPaint) {
postInvalidate(); //重新调用onDraw方法
}
}
Thread.sleep(80);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static class TextItem{
private float mLocX;
private float mLocY;
private float mSteps; //一次刷新的步进数
private int mColor;
private float mTextWidth; //文本的宽度
private String mContent;
public TextItem(String mContent) {
this.mContent = mContent;
}
public void moveLeft() {
mLocX -= mSteps;
}
public float getmLocX() {
return mLocX;
}
public void setmLocX(float mLocX) {
this.mLocX = mLocX;
}
public float getmLocY() {
return mLocY;
}
public void setmLocY(float mLocY) {
this.mLocY = mLocY;
}
public float getmSteps() {
return mSteps;
}
public void setmSteps(float mSteps) {
this.mSteps = mSteps;
}
public int getmColor() {
return mColor;
}
public void setmColor(int mColor) {
this.mColor = mColor;
}
public float getmTextWidth() {
return mTextWidth;
}
public void setmTextWidth(float mTextWidth) {
this.mTextWidth = mTextWidth;
}
public String getmContent() {
return mContent;
}
public void setmContent(String mContent) {
this.mContent = mContent;
}
}
}