效果图:
圣诞登录页.gif
参考文章:
Android自定义View——从零开始实现雪花飘落效果
感谢原文作者,不仅实现了效果,并且写得非常详细,还做了优化。笔者参考原文作者的源码,做了一点修改,实现了效果并加入了项目中。不过都大同小异,下面笔者会将学习和制作中的难点和注意点分享给大家。
提炼与分享:
1. 如何实现简单的物体下落:@Override
protected void onDraw(Canvas canvas) { super.onDraw(canvas); if(fallObjects.size()>0){ for (int i=0;i
fallObjects.get(i).drawObject(canvas);
} // 隔一段时间重绘一次, 动画效果
getHandler().postDelayed(runnable, intervalTime);
}
} private Runnable runnable = new Runnable() { @Override
public void run() {
invalidate();
}
}; public void drawObject(Canvas canvas){
moveObject();
canvas.drawBitmap(bitmap,presentX,presentY,null);
} private void moveObject(){
moveX();
moveY(); if(presentY>parentHeight || presentXparentWidth+bitmap.getWidth()){
reset();
}
} private void moveY(){
presentY += presentSpeed;
} private void moveX(){
presentX += defaultWindSpeed * Math.sin(angle); if(isAngleChange){
angle += (float) (random.nextBoolean()?-1:1) * Math.random() * 0.0025;
}
} private void reset(){
presentY = -objectHeight;
randomSpeed();
randomWind();//记得重置一下初始角度,不然雪花会越下越少(因为角度累加会让雪花越下越偏)
}
首先是Y轴控制竖直下落,初始的Y轴坐标是通过屏幕高度取随机值-屏幕高度来确定的。这样物体会从不同的位置下落,在相同速度的情况下,也能在不同的时间进入屏幕。
然后是X轴,正常的雪花肯定不是竖直下落,也不是折线下落,而是弧形,View中采用的sin函数的-Pi到Pi之间的值绘制弧形。x轴的初始位置通过对屏幕宽度做随机值确定。
最后在物体到底屏幕底部,或者超过屏幕左右边界时,重置物体(reset方法)。需要重置的是y轴的点,以及物体的速度,当然还有我们模拟的风力,后面会单独说。
2. 为什么要使用Builder建造者模式
其实原文已经讲得很仔细了,我们物体会有大量的参数和对应的行为方法,为了提高代码的可读性,我们将物体提取出来,作为一个单独的类。而大量的参数采用普通的构造方法去构造,实在是不知道,传入的参数究竟代表什么。而建造者模式能够解决这个问题。FallObject.Builder builder = new FallObject.Builder(getResources().getDrawable(R.drawable.snowflake));
FallObject fallObject = builder
.setSpeed(8,true)
.setSize(80,80,true)
.setWind(5,true)
.build(); //初始化一个雪球样式的fallObject
((FallingView)findViewById(R.id.fallingView)).addFallObject(fallObject,60);//添加60个雪球对象
在这个项目中,我们将所有与下落物体相关的方法和属性全部封装在FallObject中,并且提供Builder内部类实例化。而我们的View则仅仅需要作为一个画布,提供添加下落对象的方法,重复的绘制物体即可。至于绘制的对象是要下落还是要旋转,都与View没有关系了。
3. 绘制图片并且控制其大小
绘制图片在View中是有提供方法的:canvas.drawBitmap(bitmap,presentX,presentY,null);从方法中可以看到,我们需要的是bitmap的图片,那么,我们在修改图片大小之前,还需要先将drawable转化为bitmap。/**
* drawable图片资源转bitmap
* @param drawable
* @return
*/
public static Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap = Bitmap.createBitmap(
drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(),
drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, drawable.getIn