Android弹幕 - 定制化,支持多种样式定义的弹幕(集成B站)

Android直播间的多种弹幕效果,集成B站弹幕源码
可自定义多种样式,B站是提供了一个全局属性定义“缓存填充器”,这个“缓存填充器”可指定纯文本样式,或图文混排样式
实际上我们的需求可能会要求多种弹幕样式要求,那么就需要我们自定义这个缓存填充器样式了,定义多种样式。

以下是写的大概3种样式,没有具体的封装和扩展,这个根据自己需要看是否需要要进行封装啦。
先看下效果:
在这里插入图片描述

public class CustomActivity extends Activity {

    //弹幕控件
    private DanmakuSurfaceView mDanmakuView;
    //弹幕的上下文
    private DanmakuContext mContext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_boke_stuff);

        initDanmuKu();
    }

    private void initDanmuKu() {
        //初始化控件
        mDanmakuView = findViewById(R.id.dv);
        //对SurfaceView的设置,否则是全黑不透明的
        mDanmakuView.setZOrderOnTop(true);
        mDanmakuView.getHolder().setFormat(PixelFormat.TRANSLUCENT);

        //设置最大显示行数
        HashMap<Integer, Integer> maxLInesPair = new HashMap<>(16);
        maxLInesPair.put(BaseDanmaku.TYPE_SCROLL_RL, 3);
        //设置是否禁止重叠
        HashMap<Integer, Boolean> overlappingEnablePair = new HashMap<>(16);
        overlappingEnablePair.put(BaseDanmaku.TYPE_SCROLL_RL, true);
        overlappingEnablePair.put(BaseDanmaku.TYPE_FIX_TOP, true);
        //创建弹幕上下文
        mContext = DanmakuContext.create();
        //设置一些相关的配置
        mContext.setDuplicateMergingEnabled(false)
                //是否重复合并
                .setScrollSpeedFactor(1.5f)
                //设置文字的比例
                .setScaleTextSize(1.2f)
                //图文混排的时候使用!
                .setCacheStuffer(new CustomDanmuCacheStuff(this), mBackgroundCacheStuffer)
                //设置显示最大行数
                .setMaximumLines(maxLInesPair)
                //设置防,null代表可以重叠
                .preventOverlapping(overlappingEnablePair).setDanmakuMargin(DensityUtil.dip2px(BokeActivity.this,3));
        //设置解析器
        if (mDanmakuView != null) {
            BaseDanmakuParser defaultDanmakuParser = getDefaultDanmakuParser();
            //相应的回掉
            mDanmakuView.setCallback(new master.flame.danmaku.controller.DrawHandler.Callback() {
                @Override
                public void updateTimer(DanmakuTimer timer) {
                    //定时器更新的时候回掉
                }

                @Override
                public void drawingFinished() {
                    //弹幕绘制完成时回掉
                }

                @Override
                public void danmakuShown(BaseDanmaku danmaku) {
                    //弹幕展示的时候回掉
                }

                @Override
                public void prepared() {
                    //弹幕准备好的时候回掉,这里启动弹幕
                    mDanmakuView.start();
                }
            });
            mDanmakuView.prepare(defaultDanmakuParser, mContext);
            mDanmakuView.enableDanmakuDrawingCache(true);
        }
    }

    private BaseCacheStuffer.Proxy mBackgroundCacheStuffer = new BaseCacheStuffer.Proxy() {
        @Override
        public void prepareDrawing(BaseDanmaku danmaku, boolean fromWorkerThread) {
            // 根据你的条件检查是否需要需要更新弹幕
        }

        @Override
        public void releaseResource(BaseDanmaku danmaku) {
            //清理相应的数据
            danmaku.tag = null;
        }
    };

    //添加图片类型的弹幕
    public void addImageType(View view){
        loadImage("https://profile.csdnimg.cn/4/7/B/1_q2368465644",
                "http://img4.imgtn.bdimg.com/it/u=3764728511,3721048833&fm=26&gp=0.jpg");
    }

	//去下载图片
    private void loadImage(String avatarString, final String iconString) {
        Glide.with(BokeActivity.this).asBitmap().load(avatarString)
                .into(new SimpleTarget<Bitmap>() {
                    @Override
                    public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
                        if (resource == null) {
                            resource = BitmapFactory.decodeResource(getResources(), R.drawable.avatar_default);
                        }
                        loadTwoImage(resource, iconString);
                    }

                    @Override
                    public void onLoadFailed(Drawable errorDrawable) {
                        Bitmap resource = BitmapFactory.decodeResource(getResources(), R.drawable.avatar_default);
                        loadTwoImage(resource, iconString);
                    }
                });
    }

    private void loadTwoImage(final Bitmap avatarBitmap, final String iconString) {
        Glide.with(BokeActivity.this).asBitmap().load(iconString)
                .into(new SimpleTarget<Bitmap>() {
                    @Override
                    public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
                        if (resource == null) {
                            resource = BitmapFactory.decodeResource(getResources(), R.drawable.live_icon_header);
                        }
                        addImageTypeDanmu(avatarBitmap, resource);
                    }

                    @Override
                    public void onLoadFailed(Drawable errorDrawable) {
                        Bitmap resource = BitmapFactory.decodeResource(getResources(), R.drawable.live_icon_header);
                        addImageTypeDanmu(avatarBitmap, resource);
                    }
                });
    }

	//添加图片类型弹幕
    private void addImageTypeDanmu(Bitmap userimage, Bitmap iconbitmap){
        BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
        if (danmaku == null || mDanmakuView == null) {
            return;
        }

        Map<String, Object> map = new HashMap<>(16);
        map.put("type", "imageType");
        map.put("name", "小纠结");
        map.put("content", "在绝地求生房间送出礼物");
        map.put("bgbitmap", BitmapFactory.decodeResource(getResources(), R.drawable.live_danmu_bg_one));
        map.put("userimage", userimage);
        map.put("iconbitmap", iconbitmap);

        danmaku.tag = map;
        danmaku.text = "";
        danmaku.priority = 0;
        //是否是直播弹幕
        danmaku.setTime(mDanmakuView.getCurrentTime() + 1200);
        mDanmakuView.addDanmaku(danmaku);
    }

	//添加纯文本弹幕 - 自己的
    public void addTextType(View view){
        String name = "小纠结";
        String content = "艾瑞巴蒂666";
        BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL,mContext);
        if (danmaku == null || mDanmakuView == null) {
            return;
        }
        Map<String, Object> map = new HashMap<>(16);
        map.put("type", "textNameType");
        map.put("content", content);
        map.put("name", name);
        map.put("shadowLayer", true);

        danmaku.tag = map;
        danmaku.text = name + content;
        danmaku.setTime(mDanmakuView.getCurrentTime());
        mDanmakuView.addDanmaku(danmaku);
    }

	//添加纯文本弹幕 - 他人的
    public void addTextTypeOther(View view){
        String name = "豆豆儿";
        String content = "吉利服吉利服吉利服空投空投SKS";
        BaseDanmaku danmaku = mContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL,mContext);
        if (danmaku == null || mDanmakuView == null) {
            return;
        }
        Map<String, Object> map = new HashMap<>(16);
        map.put("type", "textNameType");
        map.put("content", content);
        map.put("name", name);
        map.put("shadowLayer", false);

        danmaku.tag = map;
        danmaku.text = name + content;
        danmaku.setTime(mDanmakuView.getCurrentTime());
        mDanmakuView.addDanmaku(danmaku);
    }

    public static BaseDanmakuParser getDefaultDanmakuParser() {
        return new BaseDanmakuParser() {
            @Override
            protected IDanmakus parse() {
                return new Danmakus();
            }
        };
    }

	//清空屏幕上的弹幕
    public void clear(View view){
        if (mDanmakuView != null) {
            mDanmakuView.clearDanmakusOnScreen();
        }
    }

	//释放弹幕
    public void release(View view){
        if (mDanmakuView != null) {
            mDanmakuView.release();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mDanmakuView != null && mDanmakuView.isPrepared()) {
            mDanmakuView.pause();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mDanmakuView != null && mDanmakuView.isPrepared() && mDanmakuView.isPaused()) {
            mDanmakuView.resume();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mDanmakuView != null) {
            // dont forget release!
            mDanmakuView.release();
            mDanmakuView = null;
        }
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        if (mDanmakuView != null) {
            // dont forget release!
            mDanmakuView.release();
            mDanmakuView = null;
        }
    }
}

以上是我们集成B站的属性初始化,以及弹幕内容的解析(拼接)。接下来就是把这些内容绘制出来了。

public class CustomDanmuCacheStuff extends BaseCacheStuffer {

    //文本弹幕
    private float TEXTDANMU_HEIGHT;
    private float TEXTDANMU_PADDINGLEFT;
    private float TEXTDANMU_PADDINGTOP;
    private float TEXTDANMU_BGHEIGHT;

    //图片类型弹幕
    private float IMAGETYPE_HEIGHT;
    private float IMAGETYPE_PADDING_TOP;
    private float IMAGETYPE_PADDING_LEFT;
    private float IMAGETYPE_IMAGE_SIZE;
    private float IMAGETYPE_MARGIN_NAME; //name左间距
    private float IMAGETYPE_MARGIN;

    //字体大小 弹幕所有字体大小一致
    private float DANMU_TEXT_SIZE;
    private float DANMU_STROKE_WIDTH;

    //文字描边radius
    private float SHADOW_RADIUS = 3.0f;
    private float SHADOW_DXY = 1f;
    private String SHADOW_COLOR = "#99000000";

    //边框
    private float SHADOW_BGRADIUS = 12f;
    private float SHADOW_BGDXY = 0.5f;
    private String SHADOW_BGCOLOR = "#FFF974";

    private Context mContext;
    //private Typeface mTypefaceflty;

    public BokeDanmuCacheStuff(Context context) {
        this.mContext = context;

        //纯文本类型弹幕 初始化
        TEXTDANMU_HEIGHT = DensityUtil.dip2px(mContext, 25);
        TEXTDANMU_PADDINGLEFT = DensityUtil.dip2px(mContext, 12);
        TEXTDANMU_PADDINGTOP = DensityUtil.dip2px(mContext, 3);
        TEXTDANMU_BGHEIGHT = DensityUtil.dip2px(mContext, 24);

        DANMU_STROKE_WIDTH = DensityUtil.dip2px(mContext, 1);
        DANMU_TEXT_SIZE = DensityUtil.dip2px(mContext, 16);

        //指定字体
        //mTypefaceflty = Typeface.createFromAsset(mContext.getAssets(), "fonnts/xxxx.TTF");

        //图片类型弹幕 初始化
        IMAGETYPE_HEIGHT = DensityUtil.dip2px(mContext, 33);
        IMAGETYPE_PADDING_TOP = DensityUtil.dip2px(mContext, 4);
        IMAGETYPE_PADDING_LEFT = DensityUtil.dip2px(mContext, 6);
        IMAGETYPE_IMAGE_SIZE = DensityUtil.dip2px(mContext, 24);
        IMAGETYPE_MARGIN_NAME = DensityUtil.dip2px(mContext, 7);
        IMAGETYPE_MARGIN = DensityUtil.dip2px(mContext, 10);
    }

    @Override
    public void measure(BaseDanmaku danmaku, TextPaint paint, boolean fromWorkerThread) {
        // 初始化数据
        Map<String, Object> map = (Map<String, Object>) danmaku.tag;
        if (map == null) return;

        String type = (String) map.get("type");
        if (type.equals("imageType")) {
            measureImageType(danmaku, paint, map);
        } else if (type.equals("textNameType")) {
            measureTextName(danmaku, paint, map);
        }
    }

    //指定要测量的弹幕的宽高 - 有图片的弹幕类型
    private void measureImageType(BaseDanmaku danmaku, TextPaint paint, Map<String, Object> map){
        String username = (String) map.get("name");
        String content = (String) map.get("content");
        Bitmap bgbitmap = (Bitmap) map.get("bgbitmap");

        //画笔
        paint.setTextSize(DANMU_TEXT_SIZE);
        //指定字体
        //paint.setTypeface(mTypefaceflty);

        float usernameLength = paint.measureText(username);
        float contentLength = paint.measureText(content);

        //弹幕区域的宽度
        danmaku.paintWidth = Math.max(IMAGETYPE_PADDING_LEFT + IMAGETYPE_IMAGE_SIZE +
                IMAGETYPE_MARGIN_NAME + usernameLength + contentLength +
                IMAGETYPE_IMAGE_SIZE +
                IMAGETYPE_MARGIN, bgbitmap.getWidth());
        //弹幕区域的高度
        danmaku.paintHeight = IMAGETYPE_HEIGHT;
    }

    //指定要测量的弹幕的宽高 - 纯文本的弹幕类型 可指定不同内容不同色值;区分本人与他人
    private void measureTextName(BaseDanmaku danmaku, TextPaint paint, Map<String, Object> map){
        String userName = (String) map.get("name");
        String content = (String) map.get("content");

        //画笔
        paint.setTextSize(DANMU_TEXT_SIZE);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(DANMU_STROKE_WIDTH);
        //指定字体
        //paint.setTypeface(mTypefaceflty);

        float usernameLength = paint.measureText(userName);
        float contentLength = paint.measureText(content);

        //弹幕区域的宽度
        danmaku.paintWidth = TEXTDANMU_PADDINGLEFT + usernameLength + contentLength + TEXTDANMU_PADDINGLEFT;
        //弹幕区域的高度
        danmaku.paintHeight = TEXTDANMU_HEIGHT;
    }

    @Override
    public void clearCaches() {

    }

    @Override
    public void drawDanmaku(BaseDanmaku danmaku, Canvas canvas, float left, float top, boolean fromWorkerThread, AndroidDisplayer.DisplayerConfig displayerConfig) {
        Map<String, Object> map = (Map<String, Object>) danmaku.tag;
        if (map == null) return;

        String type = (String) map.get("type");
        if (type.equals("imageType")) {
            drawImageType(canvas, left, top, map);
        } else if (type.equals("textNameType")) {
            drawaTextNameType(canvas, left, top, map);
        }
    }

    private void drawImageType(Canvas canvas, float left, float top, Map<String, Object> map) {
        String username = (String) map.get("name");
        String content = (String) map.get("content");

        Bitmap bgbitmap = (Bitmap) map.get("bgbitmap");
        Bitmap userimage = (Bitmap) map.get("userimage");
        Bitmap iconbitmap = (Bitmap) map.get("iconbitmap");

        //画笔
        Paint paint = new Paint();
        paint.setTextSize(DANMU_TEXT_SIZE);
        //指定字体
        //paint.setTypeface(mTypefaceflty);

        //绘制背景
        canvas.drawBitmap(bgbitmap, left, top, paint);

        //绘制头像
        float avatorLeft = left + IMAGETYPE_PADDING_LEFT;
        float avatorTop = top + IMAGETYPE_PADDING_TOP;
        float avatorRight = left + IMAGETYPE_PADDING_LEFT + IMAGETYPE_IMAGE_SIZE;
        float avatorBottom = top + IMAGETYPE_PADDING_TOP + IMAGETYPE_IMAGE_SIZE;
        canvas.drawBitmap(userimage, null, new RectF(avatorLeft, avatorTop, avatorRight, avatorBottom), paint);

        //绘制name,内容
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.FILL);

        float usernameLength = paint.measureText(username);
        float contentLength = paint.measureText(content);

        //内容
        float contentLeft = left + IMAGETYPE_IMAGE_SIZE + IMAGETYPE_MARGIN_NAME + IMAGETYPE_MARGIN_NAME + usernameLength;
        //计算文字的相应偏移量
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        //为基线到字体上边框的距离
        float textTop = fontMetrics.top;
        //为基线到字体下边框的距离
        float textBottom = fontMetrics.bottom;

        float contentBottom = top + IMAGETYPE_HEIGHT / 2;
        //基线中间点的y轴计算公式
        int baseLineY = (int) (contentBottom - textTop / 2 - textBottom / 2);
        //绘制内容
        paint.setColor(Color.parseColor("#FFFFFF"));
        canvas.drawText(content, contentLeft, baseLineY, paint);
        //绘制用户名字
        paint.setColor(Color.parseColor("#000000"));
        canvas.drawText(username, contentLeft - usernameLength, baseLineY, paint);

        float imageLeft = left + IMAGETYPE_IMAGE_SIZE + IMAGETYPE_MARGIN_NAME + IMAGETYPE_MARGIN_NAME + usernameLength + contentLength;
        float imageTop = top + IMAGETYPE_PADDING_TOP;
        float imageRight = imageLeft + IMAGETYPE_IMAGE_SIZE;
        float imageBottom = imageTop + IMAGETYPE_IMAGE_SIZE;
        canvas.drawBitmap(iconbitmap, null, new RectF(imageLeft, imageTop, imageRight, imageBottom), paint);
    }

    private void drawaTextNameType(Canvas canvas, float left, float top, Map<String, Object> map) {
        String userName = (String) map.get("name");
        String content = (String) map.get("content");
        boolean isShadowLayer = (boolean) map.get("shadowLayer");

        Paint paint = new Paint();
        paint.setTextSize(DANMU_TEXT_SIZE);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(DANMU_STROKE_WIDTH);
        //指定字体
        //paint.setTypeface(mTypefaceflty);

        float usernameLength = paint.measureText(userName);
        float contentLength = paint.measureText(content);

        if (isShadowLayer) {
            //背景边框
            paint.setColor(Color.parseColor("#3780C9"));
            paint.setShadowLayer(SHADOW_BGRADIUS, SHADOW_BGDXY, SHADOW_BGDXY, Color.parseColor(SHADOW_COLOR));
            //获取宽度
            float rectBgLeft = left + DANMU_STROKE_WIDTH;
            float rectBgTop = top + DANMU_STROKE_WIDTH;
            float rectBgRight = left + usernameLength + contentLength + TEXTDANMU_PADDINGLEFT + TEXTDANMU_PADDINGLEFT;
            float rectBgBottom = top + TEXTDANMU_BGHEIGHT;
            canvas.drawRoundRect(new RectF(rectBgLeft, rectBgTop, rectBgRight, rectBgBottom), TEXTDANMU_HEIGHT / 2, TEXTDANMU_HEIGHT / 2, paint);
        }

        //绘制弹幕内容
        paint.setColor(Color.parseColor("#3780C9"));
        paint.setStyle(Paint.Style.FILL);
        paint.setShadowLayer(SHADOW_RADIUS, SHADOW_DXY, SHADOW_DXY, Color.parseColor(SHADOW_COLOR));
        float contentLeft = left + usernameLength + TEXTDANMU_PADDINGLEFT;
        //计算文字的相应偏移量
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        //为基线到字体上边框的距离,即上图中的top
        float textTop = fontMetrics.top;
        //为基线到字体下边框的距离,即上图中的bottom
        float textBottom = fontMetrics.bottom;

        float contentBottom = top + TEXTDANMU_HEIGHT / 2;
        //基线中间点的y轴计算公式
        int baseLineY = (int) (contentBottom - textTop / 2 - textBottom / 2);
        //绘制文字
        canvas.drawText(content, contentLeft, baseLineY, paint);

        //绘制name
        paint.setColor(Color.parseColor("#29C9FF"));
        canvas.drawText(userName, contentLeft - usernameLength, baseLineY, paint);
    }

}

总结:
1.B站提供的弹幕View有DanmakuView和DanmakuSurfaceView
DanmakuSurfaceView需要设置
mDanmakuView.setZOrderOnTop(true);
mDanmakuView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
否则SurfaceView背景将不会是透明的

如果指定弹幕现在在某个布局view的下方,建议是使用DanmakuView

2.danmaku.priority 弹幕优先显示属性
如果设置了这个属性,如果瞬间属于优先显示的弹幕很多,将不会受之前设置的最大显示行数的限制
意思就是:最大显示行数的限制设置了3行,但优先显示的弹幕越多,那么这些弹幕将会排列很多行,直到这些优先弹幕飘完

3.danmaku.setTime 设置弹幕时间
这个建议不要设置时间太相近,因为在弹幕源码中的过滤器会将那些相同弹幕的时间给过滤了,所以在短时间内的比如100条弹幕会发现出现在屏幕上的弹幕不够100条

4.以上多种弹幕效果其实是按照你想要的弹幕效果进行绘制,
先弹幕宽高设置,将显示的内容进行排列绘制
指定字体,name及色值,内容及色值等,
区分的边框绘制等

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在 Android 应用中实现弹幕,可以考虑使用 SurfaceView 和 Canvas 组合来实现。 具体步骤如下: 1. 创建一个 SurfaceView,并在其上绘制弹幕。可以通过 SurfaceHolder 获取 Canvas 对象,然后在 Canvas 上绘制文本。 2. 创建一个弹幕控制器,用于控制弹幕的生成和绘制。弹幕控制器需要维护一个弹幕列表,每隔一定时间生成新的弹幕并添加到列表中。 3. 在 SurfaceView 的回调方法中,绘制弹幕列表中的所有弹幕,并更新弹幕的位置。 4. 可以根据需要添加一些特效,比如透明度渐变、移动速度变等。 示例代码如下: ```java public class DanmakuSurfaceView extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder surfaceHolder; private DanmakuController danmakuController; public DanmakuSurfaceView(Context context) { super(context); init(); } public DanmakuSurfaceView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public DanmakuSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { surfaceHolder = getHolder(); surfaceHolder.addCallback(this); danmakuController = new DanmakuController(); } @Override public void surfaceCreated(SurfaceHolder holder) { danmakuController.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { danmakuController.stop(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); List<Danmaku> danmakus = danmakuController.getDanmakus(); for (Danmaku danmaku : danmakus) { Paint paint = new Paint(); paint.setTextSize(danmaku.getTextSize()); paint.setColor(danmaku.getTextColor()); paint.setAlpha(danmaku.getAlpha()); canvas.drawText(danmaku.getText(), danmaku.getX(), danmaku.getY(), paint); } } } ``` 弹幕控制器代码示例: ```java public class DanmakuController implements Runnable { private boolean isRunning; private List<Danmaku> danmakus; public DanmakuController() { danmakus = new ArrayList<>(); } public void start() { isRunning = true; new Thread(this).start(); } public void stop() { isRunning = false; } public List<Danmaku> getDanmakus() { return danmakus; } @Override public void run() { while (isRunning) { // 生成新的弹幕并添加到列表中 Danmaku danmaku = new Danmaku(); danmakus.add(danmaku); // 更新弹幕位置 for (Danmaku d : danmakus) { d.move(); } // 每隔一定时间刷新界面 try { Thread.sleep(16); } catch (InterruptedException e) { e.printStackTrace(); } } } } ``` 弹幕类代码示例: ```java public class Danmaku { private static final int SPEED = 10; // 弹幕速度 private static final int MAX_ALPHA = 255; // 最大透明度 private String text; // 弹幕文本 private int textColor; // 弹幕颜色 private int textSize; // 弹幕字体大小 private int x; // 弹幕横坐标 private int y; // 弹幕纵坐标 private int alpha; // 弹幕透明度 public Danmaku() { text = "Hello, world!"; textColor = Color.WHITE; textSize = 36; x = 0; y = 0; alpha = MAX_ALPHA; } public String getText() { return text; } public void setText(String text) { this.text = text; } public int getTextColor() { return textColor; } public void setTextColor(int textColor) { this.textColor = textColor; } public int getTextSize() { return textSize; } public void setTextSize(int textSize) { this.textSize = textSize; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public int getAlpha() { return alpha; } public void setAlpha(int alpha) { this.alpha = alpha; } public void move() { x += SPEED; alpha -= 5; if (alpha < 0) { alpha = 0; } } } ``` 这只是一个简单的示例,实际开发中需要根据具体需求进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值