1. 程式人生 > >Android 漂浮動畫,下雪動畫效果

Android 漂浮動畫,下雪動畫效果

因工作需要最近在研究了動畫,先看下效果:

 

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的類,初始化畫筆,所需若干星星,設定不同速度

 

 
  1. private void initPaint() {

  2. paint = new Paint(Paint.ANTI_ALIAS_FLAG);

  3. // 防抖動

  4. paint.setDither(true);

  5. // 開啟影象過濾

  6. paint.setFilterBitmap(true);

  7. }

 
  1. /**

  2. * 設定動畫目標,三張大小不同,樣式不一,為了美觀

  3. * init bitmap info

  4. */

  5. private void initBitmapInfo() {

  6. mStarOne = ((BitmapDrawable) mResources.getDrawable(R.drawable.star2)).getBitmap();

  7. mStarOneWidth = mStarOne.getWidth();

  8. mStarOneHeight = mStarOne.getHeight();

  9.  
  10. mStarTwo = ((BitmapDrawable) mResources.getDrawable(R.drawable.star1)).getBitmap();

  11. mStarTwoWidth = mStarTwo.getWidth();

  12. mStarTwoHeight = mStarTwo.getHeight();

  13.  
  14. mStarThree = ((BitmapDrawable) mResources.getDrawable(R.drawable.star3)).getBitmap();

  15. mStarThreeWidth = mStarThree.getWidth();

  16. mStarThreeHeight = mStarThree.getHeight();

  17. }

 
  1. //定義三種不同快慢的漂浮速度

  2. private void initData(Context context) {

  3. mResources = getResources();

  4. DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics();

  5.  
  6. mTotalWidth = dm.widthPixels;

  7. mTotalHeight = dm.heightPixels;

  8. Log.i(TAG, "mTotalWidth=" + mTotalWidth + "--1--mTotalHeight=" + mTotalHeight);

  9. //設定三個不同大小的速度值

  10. mFloatTransLowSpeed = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0.5f,

  11. mResources.getDisplayMetrics());

  12. mFloatTransMidSpeed = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0.75f,

  13. mResources.getDisplayMetrics());

  14. mFloatTransFastSpeed = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1f,

  15. mResources.getDisplayMetrics());

  16. }

b.初始化星星,因為在構造方法裡把一些基本資料初始化結束後,接著會進行測量,我把初始化星星方法放在
onMeasure方法了

 

 

 
  1. /**

  2. * 初始化星星資訊

  3. */

  4. private void initStarInfo() {

  5.  
  6. StarInfo starInfo = null;

  7. Random random = new Random();

  8. for (int i = 0; i < mFloatCount; i++) {

  9. // 獲取星星大小比例

  10. float starSize = getStarSize(0.4f, 0.8f);

  11. //小球的座標

  12. float[] starLocation = STAR_LOCATION[i];

  13. starInfo = new StarInfo();

  14. // 初始化星星大小

  15. starInfo.sizePercent = starSize;

  16. // 初始化漂浮速度

  17. int randomSpeed = random.nextInt(3);

  18. switch (randomSpeed) {

  19. case 0:

  20. starInfo.speed = mFloatTransLowSpeed;

  21. break;

  22. case 1:

  23. starInfo.speed = mFloatTransMidSpeed;

  24. break;

  25. case 2:

  26. starInfo.speed = mFloatTransFastSpeed;

  27. break;

  28. default:

  29. starInfo.speed = mFloatTransMidSpeed;

  30. break;

  31. }

  32. // 初始化星星透明度

  33. starInfo.alpha = getStarSize(0.3f, 0.8f);

  34. // 初始化星星位置

  35. starInfo.xLocation = (int) (starLocation[0] * mTotalWidth);

  36. starInfo.yLocation = (int) (starLocation[1] * mTotalHeight);

  37. Log.i(TAG, "xLocation = " + starInfo.xLocation + "--yLocation = "

  38. + starInfo.yLocation);

  39. Log.i(TAG, "stoneSize = " + starSize + "---stoneAlpha = "

  40. + starInfo.alpha);

  41. // 初始化星星位置

  42. starInfo.direction = getStarDirection();

  43. mStarInfos.add(starInfo);

  44. }

  45. }

STAR_LOCATION[]陣列的人為的確定星星佔手機螢幕大小比例的位置,自己試過隨機生成一些資料,但是有時就扎堆了,應該找個手機螢幕上隨機不重複生成點座標的演算法,正在思考,有會的,給我說下,學習下

 

c.設定星星的移動方向,這裡只是常態化的左右上下,對角線的方向,自己可以新增其他軌跡方向

 

 
  1. /**

  2. * 不同移動軌跡,除過左右上下,也可以定義其他方向,如對角線,曲線之類的

  3. * 初始化星星執行方向

  4. */

  5. private int getStarDirection() {

  6. int randomInt;

  7. Random random = new Random();

  8. if(floatTyep==100){

  9. randomInt = random.nextInt(3);

  10. }else {

  11. randomInt=floatTyep;

  12. }

  13. int direction = 0;

  14. switch (randomInt) {

  15. case 0:

  16. direction = LEFT;

  17. break;

  18. case 1:

  19. direction = RIGHT;

  20. break;

  21. case 2:

  22. direction = TOP;

  23. break;

  24. case 3:

  25. direction = BOTTOM;

  26. break;

  27. case 4:

  28. direction = FREE_POINT;

  29. break;

  30. default:

  31. break;

  32. }

  33. return direction;

  34. }

d.重複繪製時,修改小球的運動軌跡方向,新增case型別,比如一些正餘弦軌跡,在手機上菱形執行,折線軌跡等;

 

 

 
  1. private void resetStarFloat(StarInfo starInfo) {

  2. switch (starInfo.direction) {

  3. case LEFT:

  4. if (starInfo.xLocation < -20) {

  5. starInfo.xLocation = mTotalWidth;

  6. } else {

  7. starInfo.xLocation -= starInfo.speed;

  8. }

  9.  
  10. break;

  11. case RIGHT:

  12. if (starInfo.xLocation > mTotalWidth+20) {

  13. starInfo.xLocation = 0;

  14. } else {

  15. starInfo.xLocation += starInfo.speed;

  16. }

  17.  
  18. break;

  19. case TOP:

  20. if (starInfo.yLocation < -20) {

  21. starInfo.yLocation = mTotalHeight;

  22. } else {

  23. starInfo.yLocation -= starInfo.speed;

  24. }

  25.  
  26.  
  27. break;

  28. case BOTTOM:

  29. if (starInfo.yLocation > mTotalHeight+30) {

  30. starInfo.yLocation = 0;

  31. } else {

  32. starInfo.yLocation += starInfo.speed;

  33. }

  34. break;

  35. case FREE_POINT:

  36.  
  37. if (starInfo.yLocation > mTotalHeight+30) {

  38. starInfo.yLocation = 0;

  39. } else {

  40. starInfo.yLocation += starInfo.speed;

  41. }

  42.  
  43. if (starInfo.xLocation < -20) {

  44. starInfo.xLocation = mTotalWidth;

  45. } else {

  46. starInfo.xLocation -= starInfo.speed;

  47. }

  48. break;

  49. default:

  50. break;

  51. }

  52. }

 

上面的20,30是隨便加的,是為了讓星星跑到手機螢幕之外,再重新進入介面,否則直接運動到螢幕邊界,重新開始,會閃的一下,效果不好;

e.進行繪製

 

 
  1. @Override

  2. protected void onDraw(Canvas canvas) {

  3. super.onDraw(canvas);

  4. for (int i = 0; i < mStarInfos.size(); i++) {

  5. StarInfo starInfo = mStarInfos.get(i);

  6. drawStarDynamic(i, starInfo, canvas, paint);

  7. }

  8. }

  9.  
  10. private void drawStarDynamic(int count, StarInfo starInfo,

  11. Canvas canvas, Paint paint) {

  12. resetStarFloat(starInfo);

  13. float starAlpha = starInfo.alpha;

  14. int xLocation = starInfo.xLocation;

  15. int yLocation = starInfo.yLocation;

  16. float sizePercent = starInfo.sizePercent;

  17.  
  18. xLocation = (int) (xLocation / sizePercent);

  19. yLocation = (int) (yLocation / sizePercent);

  20.  
  21. Bitmap bitmap = null;

  22. Rect srcRect = null;

  23. Rect destRect = new Rect();

  24.  
  25. mStarOneSrcRect = new Rect(0, 0, mStarOneWidth, mStarOneHeight);

  26. if (count % 3 == 0) {

  27.  
  28. bitmap = mStarOne;

  29. srcRect = mStarOneSrcRect;

  30. destRect.set(xLocation, yLocation,

  31. xLocation + mStarOneWidth, yLocation

  32. + mStarOneHeight);

  33. } else if (count % 2 == 0) {

  34. bitmap = mStarThree;

  35. srcRect = mStarThreeSrcRect;

  36. destRect.set(xLocation, yLocation, xLocation

  37. + mStarThreeWidth, yLocation + mStarThreeHeight);

  38. } else {

  39. bitmap = mStarTwo;

  40. srcRect = mStarTwoSrcRect;

  41. destRect.set(xLocation, yLocation, xLocation

  42. + mStarTwoWidth, yLocation + mStarTwoHeight);

  43. }

  44. paint.setAlpha((int) (starAlpha * 255));

  45.  
  46. canvas.save();

  47. canvas.scale(sizePercent, sizePercent);

  48. canvas.drawBitmap(bitmap, srcRect, destRect, paint);

  49. canvas.restore();

  50.  
  51. }

f.定時重會,實現動的效果

 
  1. Handler handler=new Handler(){

  2. @Override

  3. public void handleMessage(Message msg) {

  4. super.handleMessage(msg);

  5.  
  6. if(isRuning){

  7. postInvalidate();

  8. handler.sendMessageDelayed(Message.obtain(),50);

  9. }

  10. }

  11. };

 
  1. public void startAnimationFloat(){

  2. isRuning=true;

  3. handler.sendMessage(Message.obtain());

  4. }

  5.  
  6. public void stopAnimationFloat(){

  7. isRuning=false;

  8.  
  9. }

  10. public void restartAnimationFloat(){

  11. startAnimationFloat();

  12. }

基本就這些,然後在activity佈局裡使用FloatView,設定不同運動方向軌跡即可;

 

 

 
  1. protected void onCreate(Bundle savedInstanceState) {

  2. super.onCreate(savedInstanceState);

  3. setContentView(R.layout.activity_float);

  4. int typeKey = getIntent().getIntExtra("type_key", 0);

  5. FloatView startBtn = (FloatView) findViewById(R.id.float_btn);

  6. startBtn.setFloatType(FloatView.FREE_POINT);

  7. if(typeKey==1){

  8. startBtn.setFloatType(FloatView.DEFAULT_TYPE);

  9. }else if(typeKey==2){

  10. startBtn.setFloatType(FloatView.FREE_POINT);

  11. }else if(typeKey==3){

  12. startBtn.setFloatType(FloatView.TOP);

  13. }else if(typeKey==4){

  14. startBtn.setFloatType(FloatView.BOTTOM);

  15. }else if(typeKey==5){

  16. startBtn.setFloatType(FloatView.LEFT);

  17. }else if(typeKey==6){

  18. startBtn.setFloatType(FloatView.RIGHT);

  19. }

  20. startBtn.startAnimationFloat();

  21. }

以上的部分關鍵程式碼和思路學習於http://blog.csdn.net/tianjian4592/article/details/45157787,此人很牛,動畫繪製這塊文章寫的很細,容易理解,建議去看下,自己稍作修改,調通,作為筆記,來實現工作需求;
原始碼