欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 炫舞漫天飞雪效果图

程序员文章站 2024-02-20 22:25:10
今天周日,不适合出门,太冷了,俗说:一九二九不出手,三九四九零来走。。 我们的应用也可以有一些冬天的效果, 教大家做一个下雪的动画效果, 参考. 主要 (1) 隐...

今天周日,不适合出门,太冷了,俗说:一九二九不出手,三九四九零来走。。

Android 炫舞漫天飞雪效果图

我们的应用也可以有一些冬天的效果, 教大家做一个下雪的动画效果, 参考.

主要

(1) 隐藏status bar, 全屏显示图片.
(2) 绘制多个点, 实现移动效果.
(3) 回收点, 避免重复创建.

我喜欢用注释说话, 请大家多关注代码中的注释.

github下载地址

Android 炫舞漫天飞雪效果图

1. 雪花类

雪花的属性包含: 随机量, 位置, 增量, 大小, 角度, 画笔.

绘画的过程中, 使用角度会移动点的位置, 每次速率都不同.

当雪花移出屏幕时, 会重新使用, 在屏幕的顶端重新落下.

算法参考.

/**
* 雪花的类, 移动, 移出屏幕会重新设置位置.
* <p/>
* created by wangchenlong on 16/1/24.
*/
public 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; // 半pi
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 randomgenerator mrandom; // 随机控制器
private final point mposition; // 雪花位置
private float mangle; // 角度
private final float mincrement; // 雪花的速度
private final float mflakesize; // 雪花的大小
private final paint mpaint; // 画笔
private snowflake(randomgenerator random, point position, float angle, float increment, float flakesize, paint paint) {
mrandom = random;
mposition = position;
mincrement = increment;
mflakesize = flakesize;
mpaint = paint;
mangle = angle;
}
public static snowflake create(int width, int height, paint paint) {
randomgenerator random = new randomgenerator();
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);
}
// 绘制雪花
public void draw(canvas canvas) {
int width = canvas.getwidth();
int height = canvas.getheight();
move(width, height);
canvas.drawcircle(mposition.x, mposition.y, mflakesize, mpaint);
}
// 移动雪花
private void move(int width, int height) {
double x = mposition.x + (mincrement * math.cos(mangle));
double y = mposition.y + (mincrement * math.sin(mangle));
mangle += mrandom.getrandom(-angle_seed, angle_seed) / angle_divisor; // 随机晃动
mposition.set((int) x, (int) y);
// 移除屏幕, 重新开始
if (!isinside(width, height)) {
reset(width);
}
}
// 判断是否在其中
private boolean isinside(int width, int height) {
int x = mposition.x;
int y = mposition.y;
return x >= -mflakesize - 1 && x + mflakesize <= width && y >= -mflakesize - 1 && y - mflakesize < height;
}
// 重置雪花
private void reset(int width) {
mposition.x = mrandom.getrandom(width);
mposition.y = (int) (-mflakesize - 1); // 最上面
mangle = mrandom.getrandom(angle_seed) / angle_seed * ange_range + half_pi - half_angle_range;
}
}

随机数生成器, 包含区间随机和上界随机.
/**
* 随机生成器
* <p/>
* created by wangchenlong on 16/1/24.
*/
public class randomgenerator {
private static final random random = new random();
// 区间随机
public float getrandom(float lower, float upper) {
float min = math.min(lower, upper);
float max = math.max(lower, upper);
return getrandom(max - min) + min;
}
// 上界随机
public float getrandom(float upper) {
return random.nextfloat() * upper;
}
// 上界随机
public int getrandom(int upper) {
return random.nextint(upper);
}
}

2. 雪花视图

雪花视图, delay时间重绘, 绘制num_snowflakes个雪花.
初始化在onsizechanged中进行, 绘制在ondraw中进行.

/**
* 雪花视图, delay时间重绘, 绘制num_snowflakes个雪花
* <p/>
* created by wangchenlong on 16/1/24.
*/
public class snowview extends view {
private static final int num_snowflakes = 150; // 雪花数量
private static final int delay = 5; // 延迟
private snowflake[] msnowflakes; // 雪花
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);
}
@targetapi(21)
public snowview(context context, attributeset attrs, int defstyleattr, int defstyleres) {
super(context, attrs, defstyleattr, defstyleres);
}
@override protected void onsizechanged(int w, int h, int oldw, int oldh) {
super.onsizechanged(w, h, oldw, oldh);
if (w != oldw || h != oldh) {
initsnow(w, h);
}
}
private void initsnow(int width, int height) {
paint paint = new paint(paint.anti_alias_flag); // 抗锯齿
paint.setcolor(color.white); // 白色雪花
paint.setstyle(paint.style.fill); // 填充;
msnowflakes = new snowflake[num_snowflakes];
for (int i = 0; i < num_snowflakes; ++i) {
msnowflakes[i] = snowflake.create(width, height, paint);
}
}
@override protected void ondraw(canvas canvas) {
super.ondraw(canvas);
for (snowflake s : msnowflakes) {
s.draw(canvas);
}
// 隔一段时间重绘一次, 动画效果
gethandler().postdelayed(runnable, delay);
}
// 重绘线程
private runnable runnable = new runnable() {
@override
public void run() {
invalidate();
}
};
}

使用gethandler().postdelayed(runnable, delay);刷新页面.

3. 全屏布局

全屏布局

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.collapsingtoolbarlayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<framelayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<imageview
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentdescription="@null"
android:scaletype="centercrop"
android:src="@drawable/christmas"/>
<me.chunyu.spike.wcl_snowfall_demo.views.snowview
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</framelayout>
</android.support.design.widget.collapsingtoolbarlayout>

status bar默认是不会被透明化的, 需要使用collapsingtoolbarlayout,
替换status bar的样式, 否则会留有一定高度, 即使透明也不会填充.
样式

<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="apptheme.nostatusbar">
<item name="android:windowtranslucentstatus">true</item>
</style>
</resources>