博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android下雪动画的实现
阅读量:5865 次
发布时间:2019-06-19

本文共 6166 字,大约阅读时间需要 20 分钟。

  • 原文链接 :
  • 原文作者 :
  • 译文出自 :
  • 译者 :
  • 校对者:
  • 状态 : 完毕

这本是一个愉快的季节,可是。呵呵,胡扯! 由于这篇文章的发表时间是2015年的圣诞节,所以我们须要给Style Android用制造出一些节日气氛。感谢读者们,由于有的读者可能没有在庆祝圣诞,有些读者可能还是6月份。

那么问题来了,我们应该做些什么来让这个节日像是真正的节日呢? 最简单的方法:带上圣诞帽,拍个照。

tree

看我多么欢乐!

可是我感觉这个图片有些单调。所以来弄点雪花,让雪花飘下来。

我们能够加入一个包括这个图片的自己定义View

res/layout/activity_main.xml

>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.stylingandroid.snowfall.MainActivity"> <ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" android:contentDescription="@null" android:scaleType="fitCenter" android:src="@drawable/tree" /> <com.stylingandroid.snowfall.SnowView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignBottom="@id/image" android:layout_alignEnd="@id/image" android:layout_alignLeft="@id/image" android:layout_alignRight="@id/image" android:layout_alignStart="@id/image" android:layout_alignTop="@id/image" /> </RelativeLayout>

虽然能够通过继承ImageView来实现自己定义View,但我决定将 SnowView 和图片分开,这样每次刷新动画的时候不用又一次渲染图片,仅仅刷新 SnowView 即可了

SnowView.java

public class SnowView extends View {
private static final int NUM_SNOWFLAKES = 150; private static final int DELAY = 5; private SnowFlake[] snowflakes; public SnowView(Context context) { super(context); } public SnowView(Context context, AttributeSet attrs) { super(context, attrs); } public SnowView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } protected void resize(int width, int height) { Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.WHITE); paint.setStyle(Paint.Style.FILL); snowflakes = new SnowFlake[NUM_SNOWFLAKES]; for (int i = 0; i < NUM_SNOWFLAKES; i++) { snowflakes[i] = SnowFlake.create(width, height, paint); } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if (w != oldw || h != oldh) { resize(w, h); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for (SnowFlake snowFlake : snowflakes) { snowFlake.draw(canvas); } getHandler().postDelayed(runnable, DELAY); } private Runnable runnable = new Runnable() { @Override public void run() { invalidate(); } };}

代码非常easy。 在View 的 onSizeChanged 方法中初始化 150 个随机位置的雪花对象。

onDraw方法中画出雪花。然后每隔一段时间就刷新一下位置。须要注意的是onDraw没有马上去运行,而是通过创建一个runnable,这样不会堵塞UI线程

雪花下落是基于Samuel Arbesman的。

SnowFlake.java

class SnowFlake {    private static final float ANGE_RANGE = 0.1f;    private static final float HALF_ANGLE_RANGE = ANGE_RANGE / 2f;    private static final float HALF_PI = (float) Math.PI / 2f;    private static final float ANGLE_SEED = 25f;    private static final float ANGLE_DIVISOR = 10000f;    private static final float INCREMENT_LOWER = 2f;    private static final float INCREMENT_UPPER = 4f;    private static final float FLAKE_SIZE_LOWER = 7f;    private static final float FLAKE_SIZE_UPPER = 20f;    private final Random random;    private final Point position;    private float angle;    private final float increment;    private final float flakeSize;    private final Paint paint;    public static SnowFlake create(int width, int height, Paint paint) {        Random random = new Random();        int x = random.getRandom(width);        int y = random.getRandom(height);        Point position = new Point(x, y);        float angle = random.getRandom(ANGLE_SEED) / ANGLE_SEED * ANGE_RANGE + HALF_PI - HALF_ANGLE_RANGE;        float increment = random.getRandom(INCREMENT_LOWER, INCREMENT_UPPER);        float flakeSize = random.getRandom(FLAKE_SIZE_LOWER, FLAKE_SIZE_UPPER);        return new SnowFlake(random, position, angle, increment, flakeSize, paint);    }    SnowFlake(Random random, Point position, float angle, float increment, float flakeSize, Paint paint) {        this.random = random;        this.position = position;        this.angle = angle;        this.increment = increment;        this.flakeSize = flakeSize;        this.paint = paint;    }    private void move(int width, int height) {        double x = position.x + (increment * Math.cos(angle));        double y = position.y + (increment * Math.sin(angle));        angle += random.getRandom(-ANGLE_SEED, ANGLE_SEED) / ANGLE_DIVISOR;        position.set((int) x, (int) y);        if (!isInside(width, height)) {            reset(width);        }    }    private boolean isInside(int width, int height) {        int x = position.x;        int y = position.y;        return x >= -flakeSize - 1 && x + flakeSize <= width && y >= -flakeSize - 1 && y - flakeSize < height;    }    private void reset(int width) {        position.x = random.getRandom(width);        position.y = (int) (-flakeSize - 1);        angle = random.getRandom(ANGLE_SEED) / ANGLE_SEED * ANGE_RANGE + HALF_PI - HALF_ANGLE_RANGE;    }    public void draw(Canvas canvas) {        int width = canvas.getWidth();        int height = canvas.getHeight();        move(width, height);        canvas.drawCircle(position.x, position.y, flakeSize, paint);    }}

初始化的时候。雪花的随机位置就已经确定了。

这是为了确保雪花不会每次画的时候都在開始的位置。

当一个雪花的位置超出Canvas的边界之后,它就会被又一次放到顶部的一个随机位置,这样就能够循环利用了。避免了反复创建。

当画雪花下落的每一帧的时候,我们首先给SnowFlake加入一个随机数来改变位置。这样能够模仿有小风吹雪花。

在把雪花画到canvas上之前。我们会进行边界检查(假设须要的话,超出边界的就又一次放到顶部)

我一直在不断的调整里面的常量来改变下雪的效果直到我感觉惬意为止。

终于效果例如以下:

当然了,在canvas里面塞这么多东西不是一个好的方法(有其它更好的 比方OpenGL)。可是,我如今要去吃火鸡了。所以可能要等下一次了。

版权声明:

Part of this code is based upon “Snowfall” by Sam Arbesman, licensed under Creative Commons Attribution-Share Alike 3.0 and GNU GPL license.
Work: 84771
License:

© 2015, Mark Allison. All rights reserved. This article originally appeared on Styling Android.

Portions of this page are modifications based on work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License

转载地址:http://drjnx.baihongyu.com/

你可能感兴趣的文章
Python中单线程、多线程和多进程的效率对比实验
查看>>
字符串、文件操作,英文词频统计预处理
查看>>
排序算法总结(一)插入排序【Insertion Sort】
查看>>
jdk和tomcat的安装
查看>>
Cocoapods 简单的使用
查看>>
hive初体验
查看>>
onPause()是唯一一个保证在进程被杀之前会调用的,因此你应该使用onPause()来写任何持久化存储数据...
查看>>
你不可不知的HTML优化技巧(转)
查看>>
Software
查看>>
abelkhan服务器框架
查看>>
sql server 事务嵌套 并行执行
查看>>
064:ORM查询条件详解-in和关联模型查询
查看>>
js中获取数组的最大最小值
查看>>
【从传统方法到深度学习】图像分类
查看>>
前端实现图片懒加载(lazyload)的两种方式
查看>>
iOS GCD随笔
查看>>
从头开始学习数据库及ADO.NET之PostgreSql字段约束——竹子整理
查看>>
终于解决这个难题了:安装mysql server5.5 到start service未响应
查看>>
最牛B的编码套路
查看>>
strace
查看>>