c语言编程笔录

首页 >   > 笔记大全

笔记大全

h5教程利用SurfaceView实现下雨与下雪动画的效果

更新时间:2024-01-19

前言

本教程将使用SurfaceView实现下雨与下雪动画的效果。在移动应用程序开发中,使用动画效果可以提升用户体验,增加应用的吸引力。下雨和下雪动画可以模拟自然环境中的天气现象,为应用增添一丝趣味和活力。

实现下雨动画

下雨动画通常由多个垂直下落的线条组成,每个线条表示一滴雨滴。我们可以通过绘制矩形并在每次绘制过程中更新矩形的位置,来实现下雨的效果。

public class RainView extends SurfaceView implements SurfaceHolder.Callback {
    private RainThread rainThread;
    private List raindrops;

    public RainView(Context context) {
        super(context);
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);
        rainThread = new RainThread(holder);
        raindrops = new ArrayList<>();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // 初始化雨滴
        for (int i = 0; i < 100; i++) {
            RainDrop raindrop = new RainDrop(getWidth(), getHeight());
            raindrops.add(raindrop);
        }
        // 启动下雨动画线程
        rainThread.setRunning(true);
        rainThread.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // 处理SurfaceView尺寸变化的情况
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // 停止下雨动画线程
        boolean retry = true;
        rainThread.setRunning(false);
        while (retry) {
            try {
                rainThread.join();
                retry = false;
            } catch (InterruptedException e) {
                // 处理线程中断异常
            }
        }
    }

    private class RainThread extends Thread {
        private final SurfaceHolder surfaceHolder;
        private boolean running;

        public RainThread(SurfaceHolder surfaceHolder) {
            this.surfaceHolder = surfaceHolder;
            running = false;
        }

        public void setRunning(boolean running) {
            this.running = running;
        }

        @Override
        public void run() {
            Canvas canvas;
            while (running) {
                canvas = null;
                try {
                    // 获取SurfaceView的Canvas对象
                    canvas = surfaceHolder.lockCanvas();
                    synchronized (surfaceHolder) {
                        // 清空画布
                        canvas.drawColor(Color.BLACK);

                        // 更新和绘制雨滴
                        for (RainDrop raindrop : raindrops) {
                            raindrop.update();
                            raindrop.draw(canvas);
                        }
                    }
                } finally {
                    if (canvas != null) {
                        // 解锁Canvas并提交绘制结果
                        surfaceHolder.unlockCanvasAndPost(canvas);
                    }
                }
            }
        }
    }
}

public class RainDrop {
    private static final int SPEED = 10;
    private int x;
    private int y;
    private int width;
    private int height;

    public RainDrop(int screenWidth, int screenHeight) {
        x = generateRandomNumber(screenWidth);
        y = generateRandomNumber(screenHeight);
        width = generateRandomNumber(5, 10);
        height = generateRandomNumber(40, 80);
    }

    public void update() {
        y += SPEED;
        // 当雨滴超出屏幕范围时,重新设置位置
        if (y > screenHeight) {
            x = generateRandomNumber(screenWidth);
            y = generateRandomNumber(screenHeight);
            width = generateRandomNumber(5, 10);
            height = generateRandomNumber(40, 80);
        }
    }

    public void draw(Canvas canvas) {
        Paint paint = new Paint();
        paint.setColor(Color.BLUE);
        canvas.drawRect(x, y, x + width, y + height, paint);
    }

    private int generateRandomNumber(int max) {
        return new Random().nextInt(max);
    }

    private int generateRandomNumber(int min, int max) {
        return new Random().nextInt(max - min + 1) + min;
    }
}

实现下雪动画

下雪动画由多个随机漂浮的雪花组成。我们可以使用类似的方法,在每次绘制过程中更新雪花的位置,来实现下雪效果。

public class SnowView extends SurfaceView implements SurfaceHolder.Callback {
    private SnowThread snowThread;
    private List snowflakes;

    public SnowView(Context context) {
        super(context);
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);
        snowThread = new SnowThread(holder);
        snowflakes = new ArrayList<>();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // 初始化雪花
        for (int i = 0; i < 100; i++) {
            Snowflake snowflake = new Snowflake(getWidth(), getHeight());
            snowflakes.add(snowflake);
        }
        // 启动下雪动画线程
        snowThread.setRunning(true);
        snowThread.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // 处理SurfaceView尺寸变化的情况
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // 停止下雪动画线程
        boolean retry = true;
        snowThread.setRunning(false);
        while (retry) {
            try {
                snowThread.join();
                retry = false;
            } catch (InterruptedException e) {
                // 处理线程中断异常
            }
        }
    }

    private class SnowThread extends Thread {
        private final SurfaceHolder surfaceHolder;
        private boolean running;

        public SnowThread(SurfaceHolder surfaceHolder) {
            this.surfaceHolder = surfaceHolder;
            running = false;
        }

        public void setRunning(boolean running) {
            this.running = running;
        }

        @Override
        public void run() {
            Canvas canvas;
            while (running) {
                canvas = null;
                try {
                    // 获取SurfaceView的Canvas对象
                    canvas = surfaceHolder.lockCanvas();
                    synchronized (surfaceHolder) {
                        // 清空画布
                        canvas.drawColor(Color.BLACK);

                        // 更新和绘制雪花
                        for (Snowflake snowflake : snowflakes) {
                            snowflake.update();
                            snowflake.draw(canvas);
                        }
                    }
                } finally {
                    if (canvas != null) {
                        // 解锁Canvas并提交绘制结果
                        surfaceHolder.unlockCanvasAndPost(canvas);
                    }
                }
            }
        }
    }
}

public class Snowflake {
    private static final int SPEED = 5;
    private float x;
    private float y;
    private float radius;
    private float angle;

    public Snowflake(int screenWidth, int screenHeight) {
        x = generateRandomNumber(screenWidth);
        y = generateRandomNumber(screenHeight);
        radius = generateRandomNumber(5, 10);
        angle = generateRandomNumber(0, 360);
    }

    public void update() {
        x += SPEED * Math.cos(Math.toRadians(angle));
        y += SPEED * Math.sin(Math.toRadians(angle));
        // 当雪花超出屏幕范围时,重新设置位置
        if (x < 0 || x > screenWidth || y > screenHeight) {
            x = generateRandomNumber(screenWidth);
            y = generateRandomNumber(screenHeight);
            angle = generateRandomNumber(0, 360);
        }
    }

    public void draw(Canvas canvas) {
        Paint paint = new Paint();
        paint.setColor(Color.WHITE);
        canvas.drawCircle(x, y, radius, paint);
    }

    private float generateRandomNumber(float max) {
        return new Random().nextFloat() * max;
    }

    private float generateRandomNumber(float min, float max) {
        return new Random().nextFloat() * (max - min) + min;
    }
}

总结

通过SurfaceView实现下雨与下雪动画的效果,可以为移动应用程序添加一些生动和有趣的特效。通过绘制每个雨滴和雪花的位置,并在每次绘制过程中更新它们的位置,我们可以模拟出下雨和下雪的效果。在SurfaceView的回调方法中启动动画线程,并在线程中不断绘制动画效果,可以实现流畅的动画播放。希望本教程对您理解如何利用SurfaceView实现动画效果有所帮助。