Android 的漂浮动画,下雪动画效果
2016-12-24 14:24 阅读(224)

因工作需要最近在研究了动画,下文的代码取自http://blog.csdn.NET/tianjian4592/article/details/45157787,原文没有源码,但是博主把关键代码都给了,此人很牛,动画绘制这块文章写的很细,容易理解,建议去看下,自己稍作修改,调通,作为笔记,来解决他人思路,来实现工作需求;先看下效果:




1.先得了解下canvas.drawBitmap(mBitmap, mSrcRect, mDestRect, mBitPaint);

在绘制图片时,使用,参数分别,图片bitmap,绘制bitmap自己的区域,绘制bitmap在手机上显示位置区域,画笔;

mSrcRect,mDestRect都是Rect(int left, int top, int right, int bottom) 的对象;
2.思路

a.漂浮的图片,可能是小球,星星,雪花之类的,根据需求,选若干个不同小图片,先称之他们漂浮的星星;

b.根据效果,漂浮图片设置其实有关数据,像坐标,大小,透明度,移动速度进水,移动方向等;

c.然后初始化以上数据,生成批量小球,进行绘制;

d.开设个线程或handle造成定时器,来不断刷新,同时修改漂浮星星属性,

3.代码

a.定义一个继承View的类,初始化画笔,所需若干星星,设置不同速度

private void initPaint() {  
       paint = new Paint(Paint.ANTI_ALIAS_FLAG);  
       // 防抖动  
       paint.setDither(true);  
       // 开启图像过滤  
       paint.setFilterBitmap(true);  
   }
/** 
     * 设置动画目标,三张大小不同,样式不一,为了美观 
     * init bitmap info 
     */  
    private void initBitmapInfo() {  
        mStarOne = ((BitmapDrawable) mResources.getDrawable(R.drawable.star2)).getBitmap();  
        mStarOneWidth = mStarOne.getWidth();  
        mStarOneHeight = mStarOne.getHeight();  
  
        mStarTwo = ((BitmapDrawable) mResources.getDrawable(R.drawable.star1)).getBitmap();  
        mStarTwoWidth = mStarTwo.getWidth();  
        mStarTwoHeight = mStarTwo.getHeight();  
  
        mStarThree = ((BitmapDrawable) mResources.getDrawable(R.drawable.star3)).getBitmap();  
        mStarThreeWidth = mStarThree.getWidth();  
        mStarThreeHeight = mStarThree.getHeight();  
    }
//定义三种不同快慢的漂浮速度  
   private void initData(Context context) {  
       mResources = getResources();  
       DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics();  
  
       mTotalWidth = dm.widthPixels;  
       mTotalHeight = dm.heightPixels;  
       Log.i(TAG, "mTotalWidth=" + mTotalWidth + "--1--mTotalHeight=" + mTotalHeight);  
       //设置三个不同大小的速度值  
       mFloatTransLowSpeed = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0.5f,  
               mResources.getDisplayMetrics());  
       mFloatTransMidSpeed = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0.75f,  
               mResources.getDisplayMetrics());  
       mFloatTransFastSpeed = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1f,  
               mResources.getDisplayMetrics());  
   }

b.初始化星星,因为在构造方法里把一些基本数据初始化结束后,接着会进行测量,我把初始化星星方法放在
onMeasure方法了

/** 
    * 初始化星星信息 
    */  
   private void initStarInfo() {  
  
       StarInfo starInfo = null;  
       Random random = new Random();  
       for (int i = 0; i < mFloatCount; i++) {  
           // 获取星星大小比例  
           float starSize = getStarSize(0.4f, 0.8f);  
           //小球的坐标  
           float[] starLocation = STAR_LOCATION[i];  
           starInfo = new StarInfo();  
           // 初始化星星大小  
           starInfo.sizePercent = starSize;  
           // 初始化漂浮速度  
           int randomSpeed = random.nextInt(3);  
           switch (randomSpeed) {  
               case 0:  
                   starInfo.speed = mFloatTransLowSpeed;  
                   break;  
               case 1:  
                   starInfo.speed = mFloatTransMidSpeed;  
                   break;  
               case 2:  
                   starInfo.speed = mFloatTransFastSpeed;  
                   break;  
               default:  
                   starInfo.speed = mFloatTransMidSpeed;  
                   break;  
           }  
           // 初始化星星透明度  
           starInfo.alpha = getStarSize(0.3f, 0.8f);  
           // 初始化星星位置  
           starInfo.xLocation = (int) (starLocation[0] * mTotalWidth);  
           starInfo.yLocation = (int) (starLocation[1] * mTotalHeight);  
           Log.i(TAG, "xLocation = " + starInfo.xLocation + "--yLocation = "  
                   + starInfo.yLocation);  
           Log.i(TAG, "stoneSize = " + starSize + "---stoneAlpha = "  
                   + starInfo.alpha);  
           // 初始化星星位置  
           starInfo.direction = getStarDirection();  
           mStarInfos.add(starInfo);  
       }  
   }

STAR_LOCATION[]数组的人为的确定星星占手机屏幕大小比例的位置,自己试过随机生成一些数据,但是有时就扎堆了,应该找个手机屏幕上随机不重复生成点坐标的算法,正在思考,有会的,给我说下,学习下


c.设置星星的移动方向,这里只是常态化的左右上下,对角线的方向,自己可以添加其他轨迹方向

/** 
    * 不同移动轨迹,除过左右上下,也可以定义其他方向,如对角线,曲线之类的 
    * 初始化星星运行方向 
    */  
   private int getStarDirection() {  
       int randomInt;  
       Random random = new Random();  
       if(floatTyep==100){  
           randomInt = random.nextInt(3);  
       }else {  
           randomInt=floatTyep;  
       }  
       int direction = 0;  
       switch (randomInt) {  
           case 0:  
               direction = LEFT;  
               break;  
           case 1:  
               direction = RIGHT;  
               break;  
           case 2:  
               direction = TOP;  
               break;  
           case 3:  
               direction = BOTTOM;  
               break;  
           case 4:  
               direction = FREE_POINT;  
               break;  
           default:  
               break;  
       }  
       return direction;  
   }

d.重复绘制时,修改小球的运动轨迹方向,添加case类型,比如一些正余弦轨迹,在手机上菱形运行,折线轨迹等;

private void resetStarFloat(StarInfo starInfo) {  
        switch (starInfo.direction) {  
            case LEFT:  
                if (starInfo.xLocation < -20) {  
                    starInfo.xLocation = mTotalWidth;  
                } else {  
                    starInfo.xLocation -= starInfo.speed;  
                }  
  
                break;  
            case RIGHT:  
                if (starInfo.xLocation > mTotalWidth+20) {  
                    starInfo.xLocation = 0;  
                } else {  
                    starInfo.xLocation += starInfo.speed;  
                }  
  
                break;  
            case TOP:  
                if (starInfo.yLocation < -20) {  
                    starInfo.yLocation = mTotalHeight;  
                } else {  
                    starInfo.yLocation -= starInfo.speed;  
                }  
  
  
                break;  
            case BOTTOM:  
                if (starInfo.yLocation > mTotalHeight+30) {  
                    starInfo.yLocation = 0;  
                } else {  
                    starInfo.yLocation += starInfo.speed;  
                }  
                break;  
            case FREE_POINT:  
  
                if (starInfo.yLocation > mTotalHeight+30) {  
                    starInfo.yLocation = 0;  
                } else {  
                    starInfo.yLocation += starInfo.speed;  
                }  
  
                if (starInfo.xLocation < -20) {  
                    starInfo.xLocation = mTotalWidth;  
                } else {  
                    starInfo.xLocation -= starInfo.speed;  
                }  
                break;  
            default:  
                break;  
        }  
    }

上面的20,30是随便加的,是为了让星星跑到手机屏幕之外,再重新进入界面,否则直接运动到屏幕边界,重新开始,会闪的一下,效果不好;

e.进行绘制

@Override  
   protected void onDraw(Canvas canvas) {  
       super.onDraw(canvas);  
       for (int i = 0; i < mStarInfos.size(); i++) {  
           StarInfo starInfo = mStarInfos.get(i);  
           drawStarDynamic(i, starInfo, canvas, paint);  
       }  
   }  
  
   private void drawStarDynamic(int count, StarInfo starInfo,  
                                Canvas canvas, Paint paint) {  
       resetStarFloat(starInfo);  
       float starAlpha = starInfo.alpha;  
       int xLocation = starInfo.xLocation;  
       int yLocation = starInfo.yLocation;  
       float sizePercent = starInfo.sizePercent;  
  
       xLocation = (int) (xLocation / sizePercent);  
       yLocation = (int) (yLocation / sizePercent);  
  
       Bitmap bitmap = null;  
       Rect srcRect = null;  
       Rect destRect = new Rect();  
  
       mStarOneSrcRect = new Rect(0, 0, mStarOneWidth, mStarOneHeight);  
       if (count % 3 == 0) {  
  
           bitmap = mStarOne;  
           srcRect = mStarOneSrcRect;  
           destRect.set(xLocation, yLocation,  
                   xLocation + mStarOneWidth, yLocation  
                           + mStarOneHeight);  
       } else if (count % 2 == 0) {  
           bitmap = mStarThree;  
           srcRect = mStarThreeSrcRect;  
           destRect.set(xLocation, yLocation, xLocation  
                   + mStarThreeWidth, yLocation + mStarThreeHeight);  
       } else {  
           bitmap = mStarTwo;  
           srcRect = mStarTwoSrcRect;  
           destRect.set(xLocation, yLocation, xLocation  
                   + mStarTwoWidth, yLocation + mStarTwoHeight);  
       }  
       paint.setAlpha((int) (starAlpha * 255));  
  
       canvas.save();  
       canvas.scale(sizePercent, sizePercent);  
       canvas.drawBitmap(bitmap, srcRect, destRect, paint);  
       canvas.restore();  
  
   }

f.定时重会,实现动的效果

Handler handler=new Handler(){  
      @Override  
      public void handleMessage(Message msg) {  
          super.handleMessage(msg);  
  
          if(isRuning){  
              postInvalidate();  
              handler.sendMessageDelayed(Message.obtain(),50);  
          }  
      }  
  };
public void startAnimationFloat(){  
       isRuning=true;  
       handler.sendMessage(Message.obtain());  
   }  
  
   public void stopAnimationFloat(){  
       isRuning=false;  
  
   }  
   public void restartAnimationFloat(){  
       startAnimationFloat();  
   }

基本就这些,然后在activity布局里使用FloatView,设置不同运动方向轨迹即可;

protected void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     setContentView(R.layout.activity_float);  
     int typeKey = getIntent().getIntExtra("type_key", 0);  
     FloatView startBtn = (FloatView) findViewById(R.id.float_btn);  
     startBtn.setFloatType(FloatView.FREE_POINT);  
     if(typeKey==1){  
         startBtn.setFloatType(FloatView.DEFAULT_TYPE);  
     }else if(typeKey==2){  
         startBtn.setFloatType(FloatView.FREE_POINT);  
     }else if(typeKey==3){  
         startBtn.setFloatType(FloatView.TOP);  
     }else if(typeKey==4){  
         startBtn.setFloatType(FloatView.BOTTOM);  
     }else if(typeKey==5){  
         startBtn.setFloatType(FloatView.LEFT);  
     }else if(typeKey==6){  
         startBtn.setFloatType(FloatView.RIGHT);  
     }  
     startBtn.startAnimationFloat();  
 }

源码