Android 炫舞漫天飞雪效果图
程序员文章站
2023-12-22 14:50:04
今天周日,不适合出门,太冷了,俗说:一九二九不出手,三九四九零来走。。
我们的应用也可以有一些冬天的效果, 教大家做一个下雪的动画效果, 参考.
主要
(1) 隐...
今天周日,不适合出门,太冷了,俗说:一九二九不出手,三九四九零来走。。
我们的应用也可以有一些冬天的效果, 教大家做一个下雪的动画效果, 参考.
主要
(1) 隐藏status bar, 全屏显示图片.
(2) 绘制多个点, 实现移动效果.
(3) 回收点, 避免重复创建.
我喜欢用注释说话, 请大家多关注代码中的注释.
github下载地址
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>
推荐阅读