Android下雪动画的实现
- 原文链接 : Snowfall
- 原文作者 : Styling Android
- 译文出自 : hanks.xyz
- 译者 : hanks-zyh
- 校对者: desmond1121
- 状态 : 完毕
这本是一个愉快的季节,可是。呵呵,胡扯! 由于这篇文章的发表时间是2015年的圣诞节,所以我们须要给Style Android用制造出一些节日气氛。感谢读者们,由于有的读者可能没有在庆祝圣诞,有些读者可能还是6月份。
那么问题来了,我们应该做些什么来让这个节日像是真正的节日呢? 最简单的方法:带上圣诞帽,拍个照。
看我多么欢乐!
可是我感觉这个图片有些单调。所以来弄点雪花,让雪花飘下来。
我们能够加入一个包括这个图片的自己定义View
res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?
>
<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上之前。我们会进行边界检查(假设须要的话,超出边界的就又一次放到顶部)
我一直在不断的调整里面的常量来改变下雪的效果直到我感觉惬意为止。
终于效果例如以下:
youtube
当然了,在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: http://openprocessing.org/visuals/?visualID= 84771
License:
http://creativecommons.org/licenses/by-sa/3.0/
http://creativecommons.org/licenses/GPL/2.0/
© 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
Android下雪动画的实现的更多相关文章
- Android属性动画
这几天看郭神的博客 Android属性动画完全解析(上),初识属性动画的基本用法之后,我自己突然想实现一种动画功能,就是我们在携程网.阿里旅行等等手机APP端买火车票的时候,看到有选择城市,那么就有出 ...
- android 自定义动画
android自定义动画注意是继承Animation,重写里面的initialize和applyTransformation,在initialize方法做一些初始化的工作,在applyTransfor ...
- 【转】android 属性动画之 ObjectAnimator
原文网址:http://blog.csdn.net/feiduclear_up/article/details/39255083 前面一篇博客讲解了 android 简单动画之 animtion,这里 ...
- Android属性动画之ValueAnimation
ValueAnimation是ObjectAnimation类的父类,经过前几天的介绍,相信大家对ObjectAnimation有了 一定的认识,今天就为大家最后介绍一下ValueAnimation, ...
- Android属性动画之ObjectAnimator
相信对于Android初学者,对于Android中的动画效果一定很感兴趣,今天为大家总结一下刚刚学到的属性动画案例. 首先和一般的Android应用一样,我们先建一个工程,为了方便,我们的布局文件中就 ...
- 79.Android之动画基础
转载:http://a.codekk.com/detail/Android/lightSky/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8 ...
- Android属性动画完全解析(下)
转载:http://blog.csdn.net/guolin_blog/article/details/44171115 大家好,欢迎继续回到Android属性动画完全解析.在上一篇文章当中我们学习了 ...
- Android属性动画完全解析(上),初识属性动画的基本用法
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/43536355 在手机上去实现一些动画效果算是件比较炫酷的事情,因此Android系 ...
- Android属性动画完全解析(中)
转载:http://blog.csdn.net/guolin_blog/article/details/43536355 大家好,在上一篇文章当中,我们学习了Android属性动画的基本用法,当然也是 ...
随机推荐
- Unity3D 的大场景内存优化
我们公司的一个 MMORPG 项目最近在内存方面碰到了红线,昨天开会讨论了一下.我提出了一个改进方案,写篇 blog 记录一下. 问题是这样的.在当下的手机及平板硬件设备条件下,操作系统留给应用的可用 ...
- svn: E155015: 提交失败(细节如下) 解决办法
svn 出现冲突是经常发生的事,最近改用命令操作svn,用界面电脑有些反应慢 出现冲突使用svn 命令肯定也是可以解决的: 查看警告信息提示冲突的文件,执行 svn resolved <文件名& ...
- C C++ 去除 unused的提示
C C++ 去除 unused的提示 #define UNUSED(VAR) {VAR++;VAR--;} unsigned int user_id=0; UNUSED(user_id); 这样就可以 ...
- sharepoint 2010 自定义页面布局
在sharepoint开发中经常遇到 自定义网站栏.内容类型,页面布局和模板页也会遇到,遇到机会就相对比较小. 首先新建一个空的sharepoint项目: 1)创建网站兰: 修改SiteColumns ...
- Gradle Groovy 基础语法 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- 构建配置 ProGuard Shrink 混淆和压缩
官方文档 压缩代码和资源 要尽可能减小 APK 文件,您应该启用压缩来移除 release build 中未使用的代码和资源.此页面介绍如何执行该操作,以及如何指定要在构建时保留或舍弃的代码和资源. ...
- Java程序员须知的七个日志管理工具
本文由 ImportNew - 赖 信涛 翻译自 takipiblog.欢迎加入翻译小组.转载请见文末要求. Splunk vs. Sumo Logic vs. LogStash vs. GrayLo ...
- CSS布局中一个简单的应用BFC的例子
什么是BFC BFC(Block Formatting Context),简单讲,它是提供了一个独立布局的环境,每个BFC都遵守同一套布局规则.例如,在同一个BFC内,盒子会一个挨着一个的排,相邻盒子 ...
- vue嵌套路由总结
嵌套路由就是在一个被路由过来的页面下可以继续使用路由,嵌套也就是路由中的路由的意思. 比如在vue中,我们如果不使用嵌套路由,那么只有一个<router-view>,但是如果使用,那么在一 ...
- 揭秘uc浏览器三
这节我们主要讨论收藏与历史记录页面的边边角角. 首先,看看他的最终的效果图了: 照例了,我们先看看他的布局文件: <!-- tab布局文件 --> <TabHost xmlns:an ...