安卓Android弹幕功能实现-使用SurfaceView |
---|
先来一张效果图

每一条弹幕其实都是一个文本,用drawText即可绘制,我们可以建立一个集合用来存储弹幕,动态改变弹幕的X轴,即可移动弹幕,当弹幕移出屏幕时,再进行销毁操作。
第一步:新建mSurfaceView类,继承SurfaceView,并实现SurfaceHolder.Callback以及Runnable接口 |
|
public class mSurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable{
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
Flag=false;
}
@Override
public void run() { }
}
//用于标注线程是否继续
private boolean Flag=true;
//SurfaceHolder
SurfaceHolder surfaceHolder;
//弹幕的集合
public List<mText> Barrages=new ArrayList<>();
//用于随机生成弹幕的Y轴坐标
Random random=new Random();
public mSurfaceView(Context context) {
super(context);
}
public mSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
surfaceHolder=getHolder();
surfaceHolder.addCallback(this);
//设置背景透明
this.setZOrderOnTop(true);
surfaceHolder.setFormat(PixelFormat.TRANSLUCENT);
}
public mSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
前面说过,每一条弹幕都需要存入集合,绘制的时候再遍历集合取出里面的弹幕进行绘制,那下面第三步:添加弹幕类 |
---|
public class mText {
//文字
private String text;
//文字大小
private float size;
//文字颜色
private Integer color;
//文字X轴
private float x;
//文字Y轴
private float y;
//文字移动速度
private int speed;
//画笔
private Paint paint;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public float getSize() {
return size;
}
public void setSize(float size) {
this.size = size;
}
public Integer getColor() {
return color;
}
public void setColor(Integer color) {
this.color = color;
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public Paint getPaint() {
return paint;
}
public void setPaint(Paint paint) {
this.paint = paint;
}
}
其实大家可能注意到,上方弹幕类中,定义有文字内容、文字颜色、文字大小等成员变量,既然有颜色、大小等,那我们为什么还有定义画笔呢?
其实画笔可以传一个null,考虑到有时候仅靠颜色和大小可能无法完全满足我们的需求,所以我们可以定义一个画笔,更方便扩展,如果传过来了画笔,则直接用画笔进行绘制,如果画笔为null,则用默认的画笔,通过类中的颜色、大小等进行绘制。
既然已经定义弹幕类,那肯定也需要添加弹幕到弹幕集合的方法,第四步:定义add方法: |
---|
//添加弹幕
public void add(mText mText) {
if (mText.getX()==0){
mText.setX(getWidth());
}
if (mText.getY()==0){
int i=getHeight();
if (i>0){
mText.setY(random.nextInt(i));
}
}
Barrages.add(mText);
}
大家看到,上面有对x和y轴参数的非空判断,这样做的目的是当我们在调用add方法时,可以不给mText类的x、y赋值,节省我们的时间,如果检测到y轴为0,就随机指定一个y轴,如果x轴为0,则默认从屏幕的最右侧开始。
@Override
public void run() {
Canvas canvas=null;
mText mtext = null;
Paint paint=null;
while (Flag){
//如果集合为0,则跳过本次循环
if (Barrages.size()==0){
continue;
}
try {
//获取画布
canvas=surfaceHolder.lockCanvas();
//清空画布
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
}catch (Exception e){
e.printStackTrace();
break;
}
//遍历弹幕集合
for (int i = 0; i < Barrages.size(); i++) {
mtext=Barrages.get(i);
//如果弹幕类中的画笔为空,则在此处定义画笔,根据弹幕类中的颜色大小等进行绘制
if (mtext.getPaint()==null){
if (paint==null){
paint=new Paint();
}
paint.setColor(mtext.getColor());
paint.setTextSize(mtext.getSize());
paint.setStrokeWidth(3f);
}else {
//如果弹幕类中的画笔不为空,则直接用弹幕类中的画笔绘制
paint=mtext.getPaint();
}
//绘制文本
canvas.drawText(mtext.getText(),mtext.getX(),mtext.getY(),paint);
//如果弹幕超出屏幕左侧,则从集合中删除,否则进行移动
if (mtext.getX()<-getWidth()){
Barrages.remove(mtext);
}else {
mtext.setX((mtext.getX()-mtext.getSpeed()));
}
}
//解锁画布
surfaceHolder.unlockCanvasAndPost(canvas);
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
大功告成,我们来看看如何调用,只需要执行msurfaceview.add方法添加弹幕即可。 |
---|
public class MainActivity extends Activity {
private mSurfaceView msurfaceView;
private VideoView videoView;
private Random random=new Random();
private String[] strings={"6666","厉害了我的国","加油!!!","欢迎收看晨间新闻","程序猿很苦逼","我能怎么办,我也很无奈"};
private int[] colors={Color.WHITE,Color.MAGENTA,Color.CYAN,Color.RED,Color.BLUE,Color.GREEN};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
msurfaceView = findViewById(R.id.msv);
videoView = findViewById(R.id.mvv);
//申请播放网络视频权限
per();
startVideo();
//动态生成弹幕
startBarrage();
}
//生成弹幕
private void startBarrage() {
new Thread(new Runnable() {
@Override
public void run() {
while (true){
mText mText=new mText();
mText.setText(strings[random.nextInt(strings.length)]);
mText.setSpeed(3);
mText.setColor(colors[random.nextInt(colors.length)]);
mText.setSize(40);
msurfaceView.add(mText);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
//申请视频播放权限
private void per() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {//检查是否有了权限
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
} else {
//没有权限即动态申请
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
}
}
}
//开始播放视频
private void startVideo() {
String url1 = "http://flashmedia.eastday.com/newdate/news/2016-11/shznews1125-19.mp4";
Uri uri=Uri.parse(url1);
//设置视频控制器
videoView.setMediaController(new MediaController(this));
//设置视频路径
videoView.setVideoURI(uri);
//开始播放视频
videoView.start();
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<VideoView
android:id="@+id/mvv"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<barrage.surfaceview.com.surfaceviewbarragedemo.mSurfaceView
android:id="@+id/msv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
github完整代码地址:安卓Android弹幕效果实现
PS:如有不正确的地方欢迎指出!
转载请注明:https://blog.****.net/weixin_41549915/article/details/80306476