首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >圣诞雪花纷飞自定义View

圣诞雪花纷飞自定义View

作者头像
蜻蜓队长
发布2018-08-03 11:32:30
5710
发布2018-08-03 11:32:30
举报
文章被收录于专栏:Android机动车Android机动车

github地址:https://github.com/shuaijia/JSBaseDemo/blob/master/app/src/main/java/com/jia/demo/view/SnowView.java

先定义下实体类吧:

/**
 * Description: 雪花效果实体类
 * Created by jia on 2017/12/25.
 * 人之所以能,是相信能
 */
public class Snow {
    private float x;
    private float y;
    private int alfa;
    private float size;
    private float speed;
    private int srcType;
    public Snow(float x, float y, int alfa, float size, float speed, int srcType) {
        this.x = x;
        this.y = y;
        this.alfa = alfa;
        this.size = size;
        this.speed = speed;
        this.srcType = srcType;
    }
    ...// get、set方法省略
}

实现思路:

说起这种雪花纷飞的效果,大家都会立刻想到用属性动画,通过各种动画组合、插值器的使用(当然使用贝塞尔曲线会更炫),就可以很轻松的实现如上效果,但我们今天换种思路来实现:

因为所有的雪花需要实时在移动位置,所以想开启子线程去控制所以雪花位置,但因为在子线程中刷新view,就采用SurfaceView来实现。

SurfaceView继承之View,但拥有独立的绘制表面,即它不与其宿主窗口共享同一个绘图表面,可以单独在一个线程进行绘制,并不会占用主线程的资源。

自定义view

    public SnowView(Context context, AttributeSet attrs) {
        super(context, attrs);
        surfaceHolder = this.getHolder();
        surfaceHolder.addCallback(this);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        bgBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.snow_bg);
        init();
    }
    private void init() {
        DisplayMetrics dm = getResources().getDisplayMetrics();
        snows = new ArrayList<>();
        float x, y, size, speed;
        int alfa, srcType;
        for (int i = 0; i < maxCount; i++) {
            x = (float) Math.floor(Math.random() * dm.widthPixels);//初始X坐标
            y = (float) Math.floor(Math.random() * dm.heightPixels);//初始Y坐标
            size = (float) ((Math.random() * 15f) + 20f);//初始半径
            speed = (float) ((Math.random() * 6) + 5);
            alfa = (int) Math.floor(100 * Math.random() + 155);
            srcType = (int) (Math.random() + 0.5);
            snows.add(new Snow(x, y, alfa, size, speed, srcType));
        }
    }

初始化SnowView,我们定义一屏雪花数(如100),循环100次,使用随机数设置雪花位置、大小、透明度等属性,并放入集合中。

    /**
     * 绘制进程
     */
    class DrawThread extends Thread {
        public boolean isRunning = false;
        private Canvas canvas;
        public DrawThread() {
            isRunning = true;
        }
        @Override
        public void run() {
            super.run();
            while (isRunning) {
                synchronized (surfaceHolder) {
                    // Start editing the pixels in the surface.  The returned Canvas can be used to draw into the surface's bitmap.
                    canvas = surfaceHolder.lockCanvas();
                    drawSprite(canvas);
                    for (int i = 0; i < maxCount; i++) {
                        curSnow = snows.get(i);
                        float size = curSnow.getSize();
                        float speed = curSnow.getSpeed();
                        int alfa = curSnow.getAlfa();
                        float x = curSnow.getX();
                        float y = curSnow.getY() + speed;
                        int type = curSnow.getSrcType();
                        if (y >= canvas.getHeight() || x >= canvas.getWidth()) {
                            y = 0;
                            x = (float) Math.floor(Math.random() * canvas.getWidth());//初始X坐标
                        }
                        mPaint.setAlpha(alfa);
                        Bitmap snowBitmap;
                        if (type == 1) {
                            snowBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.snow1);
                        } else {
                            snowBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.snow2);
                        }
                        RectF rect = new RectF(x, y, x + size, y + size);
                        canvas.drawBitmap(snowBitmap, null, rect, mPaint);
                        snows.set(i, new Snow(x, y, alfa, size, speed, type));
                    }
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
            }
        }
        public void stopThread() {
            isRunning = false;
            boolean workIsNotFinish = true;
            while (workIsNotFinish) {
                try {
                    this.join();// 保证run方法执行完毕
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                workIsNotFinish = false;
            }
        }
    }
    private void drawSprite(Canvas canvas) {
        //清屏操作
        canvas.drawBitmap(bgBitmap, null, new Rect(0, 0, canvas.getWidth(), canvas.getHeight()), null);
    }

在run方法中获取到当前绘制的canvas,然后循环进行绘制,绘制完成后surfaceHolder.unlockCanvasAndPost(canvas),将画布显示在屏幕上。

注意整个循环执行次数多,但我们必须保证全部绘制完再切换线程,所以我们使用synchronized关键字。

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if (null == mDrawThread) {
            mDrawThread = new DrawThread();
            mDrawThread.start();
        }
    }
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (null != mDrawThread) {
            mDrawThread.stopThread();
        }
    }

在surface创建的回调中开启线程,在destroy方法中关闭线程,就ok了!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-12-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android机动车 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 先定义下实体类吧:
  • 自定义view
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档