• 原文链接 : 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);}}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);if (w != oldw || h != oldh) {resize(w, h);}}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);for (SnowFlake snowFlake : snowflakes) {snowFlake.draw(canvas);}getHandler().postDelayed(runnable, DELAY);}private Runnable runnable = new Runnable() {@Overridepublic void run() {invalidate();}};
}

代码很简单。 在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下雪动画的实现相关推荐

  1. Android下雪动画 VS JS下雪动画

    Android下雪动画的实现 自定义View package com.shanjing.snowflake;import android.content.Context; import android ...

  2. android下雪动画demo,Android的漂浮动画,下雪动画效果剖析.doc

    Android的漂浮动画,下雪动画效果剖析 Android 的漂浮动画,下雪动画效果 先看下效果: 1.先得了解下canvas.drawBitmap(mBitmap, mSrcRect, mDestR ...

  3. Android 下雪动画

    原文链接 : Snowfall 原文作者 : Styling Android 译文出自 : hanks.xyz 译者 : hanks-zyh 校对者: desmond1121 状态 : 完成 这本是一 ...

  4. android 下雪动画,自定义下雪动画(上)

    本章目录 Part One:构造方法 Part Two:自定义属性 Part Three:布局测量 Part Four:绘制 Part Five:重绘 在了解了自定义View的基本绘制流程后,还需要大 ...

  5. android下雪动画图片,CSS3 下雪的背景动画

    CSS 语言: CSSSCSS 确定 .snow-container { position: absolute; height: 500px; width: 100%; max-width: 100% ...

  6. android 自定义loading,Android自定义动画-StarLoadingView

    今天来分享第二个自定义loading的动画,起了个名字叫 蹦跶的星星 ,还是老规矩先介绍,后上图. 实现效果在最后,GIF有点大,手机流量慎重. 介绍 首先声明做这个动画的初衷是为了学习和分享,所以从 ...

  7. android 三维动画效果,9款令人惊叹的HTML5 3D动画应用

    原标题:9款令人惊叹的HTML5 3D动画应用 之前我们已经向大家分享了很多HTML5动画应用了,大部分都非常炫酷,也有一小部分是很实用的.今天我们要向各位HTML5动画爱好者介绍更多的HTML5 3 ...

  8. 【学习笔记】Android视图动画学习

    2019独角兽企业重金招聘Python工程师标准>>> 1.Android View动画框架 Animation框架定义了透明度.旋转.缩放和位移几种常见的动画. 实现原理:每次绘制 ...

  9. android矢量动画 充电,android矢量动画

    android矢量动画! 直接来个例子就明白了!(这里我把与动画无关的属性都用-表示) 首先你要有个矢量图 比如这个矢量图xml文件叫"vector1",文件在res\drawab ...

最新文章

  1. 比特币的价格今年会达到10万美元吗?有人用蒙特卡罗方法预测了一下
  2. camunda视频教程_【Camunda工作流(1)工作笔记:SpringBoot整合Camunda】
  3. hdu2588 GCD
  4. Java设计模式 之 工厂方法模式
  5. python 线性回归 技术方案亮点_基于Python的线性回归实战
  6. arm926ej_EJB超时策略:它们如何提供帮助?
  7. CSS3伪元素、伪类选择器
  8. opensource项目_最佳Opensource.com:法律
  9. 中国的城市看多了,贴贴美国的城市,肯定对你的视觉产生冲击
  10. supervisor、pm2、forever坐下来聊聊
  11. 应急响应之ARP欺骗
  12. ReentrantReadWriteLock源码解读
  13. windows自带黑体_微软黑体下载-微软黑体官方下载[字体下载]-华军软件园
  14. Learning AV Foundation(二)AVAudioPlayer
  15. Jetpack:Room超详细使用踩坑指南!
  16. 8乘8led点阵显示数字_8乘以8点阵显示依次从左往右全部点亮,有老哥有51编程语言吗?...
  17. XGBoost原理介绍
  18. Android Studio飘红错误
  19. 【手把手带你Godot游戏开发】FlappyBird:4.1无限地面之Godot青年(AnimationPlayer)版
  20. 关于打包处理less文件时遇见的问题:

热门文章

  1. Calico集成kubernetes的CNI网络部署全过程、启用CA自签名
  2. STM32工程模板简单套用教程(Keil MDK)
  3. SAP ABAP 查询物料的销售/生产消耗数据
  4. 恐怖的计算机病毒,电脑上突然出现恐怖病毒,有没有吓到你
  5. 失眠,开灯,看书,看数学书!
  6. Java 后端开发面试总结:25 个技术专题(最全面试攻略)
  7. C++中goto的使用
  8. 《人民的名义》如何圈粉“90后”| 大数据舆情分析
  9. antd Upload手动上传(react)
  10. 第十届蓝桥杯C/C++ B组决赛