android实现icon动态旋转效果

本文实例为大家分享了android实现icon动态旋转效果的具体代码,供大家参考,具体内容如下

碰到客户的这样一个需求,点击icon后,前景的icon开始旋转,背景的icon不动,就是这样一个效果

通过第三方的方法是不可能实现的,我这里是通过修改系统launcher的代码来实现。实现思路是在launcher中找到显示icon图标代码,并把这个图标覆盖掉。很多第手机的时钟icon是可以动态变化的,好在公司已经有人实现这个功能,可以借鉴

我这里先把时钟动态icon的实现说明下,需要的朋友可以参考。

写一个IconScript的基类继承Drawable

package com.android.launcher3; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.view.View; import android.util.Log; public class IconScript extends Drawable{       public boolean isRuning = false;       public FastBitmapDrawable mFastBitmapDrawable = null;       protected Paint mPaint = new Paint();       public IconScript(){           mPaint.setAntiAlias(true);            mPaint.setFilterBitmap(true);       }       public void draw(Canvas canvas){           if(mFastBitmapDrawable != null){               Log.e("fly","IconScript=");             canvas.drawBitmap(mFastBitmapDrawable.getBitmap(), null, getBounds(),mPaint);//画底图           }       }       /**       * 运行脚本       * @param view       */       public void run(View view){           isRuning = true;       }       /**       * 停止脚本       * (未调用,暂留入口)       */       public void onStop(){           isRuning = false;       }       /**       * 暂停脚本       * (未调用,暂留入口)       */       public void onPause(){           isRuning = false;       }       /**       * 恢复脚本       * (未调用,暂留入口)       */       public void onResume(){           isRuning = true;       }       @Override       public int getOpacity() {           // TODO Auto-generated method stub           return 0;       }       @Override       public void setAlpha(int arg0) {           // TODO Auto-generated method stub       }       @Override       public void setColorFilter(ColorFilter arg0) {           // TODO Auto-generated method stub       }       @Override       public int getIntrinsicWidth() {           int width = getBounds().width();           if (width == 0) {               width = mFastBitmapDrawable.getBitmap().getWidth();           }           return width;       }       @Override       public int getIntrinsicHeight() {           int height = getBounds().height();           if (height == 0) {               height = mFastBitmapDrawable.getBitmap().getHeight();           }           return height;       }       @Override       public int getMinimumWidth() {           return getBounds().width();       }       @Override       public int getMinimumHeight() {           return getBounds().height();       }       @Override       public void setFilterBitmap(boolean filterBitmap) {           mPaint.setFilterBitmap(filterBitmap);           mPaint.setAntiAlias(filterBitmap);       }       public void setFastBitmapDrawable(FastBitmapDrawable drawable){           mFastBitmapDrawable = drawable;       }       public FastBitmapDrawable setFastBitmapDrawable(){           return mFastBitmapDrawable;       }   }  

核心类ClockScript继承IconScript

package com.android.launcher3; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.text.format.Time; import android.view.View; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; public class ClockScript extends IconScript {      Rect mRect = null;      /**      * 效果展示目标View      */      private View mView;      /**      * 通知系统更新视图现成      */      private ClockThread mClockThread = null;      /**      * 当前是否显示在屏幕上      */      private boolean mIsShowInScreen = false;      Context mContext;     public ClockScript(Context context){          super();       mContext = context;      }      public void run(View view) {          mView = view;          mRect = getBounds();          if(mClockThread == null){              mClockThread = new ClockThread();              mClockThread.start();          }      }      @Override      public void onPause() {          mClockThread.pauseRun();          super.onPause();      }      @Override      public void onResume() {          mClockThread.resumeRun();          super.onResume();      }      @Override      public void onStop() {          mClockThread.stopRun();          super.onStop();      }      @Override      public void draw(Canvas canvas) {          super.draw(canvas);          mIsShowInScreen = true;          drawIndicator(canvas,mRect.centerX(),mRect.centerY(),mPaint);          if(mClockThread.wait){              mClockThread.resumeRun();          }      }      /**      * 画指针      * @param canvas      * @param centerX      * @param centerY      * @param p      */    private void drawIndicator(Canvas canvas,int centerX,int centerY,Paint p){       Bitmap clockIcon = Utilities.createIconBitmap( BitmapFactory.decodeResource(mContext.getResources(), R.drawable.ic_launcher_clock),mContext);       int X = clockIcon.getWidth()/2;     int Y = clockIcon.getHeight()/2;     canvas.drawBitmap(clockIcon, null, getBounds(),p);//画底图       Time t=new Time();      t.setToNow();      p.setAntiAlias(true);     p.setStrokeWidth(3);     p.setColor(Color.WHITE);     p.setStyle(Paint.Style.FILL); //hour canvas.drawLine(X, Y, int)(X + (clockIcon.getWidth()/2-35) * Math.cos((t.hour+(float)t.minute/60) * (Math.PI / 6) - Math.PI / 2)), (int)(Y + (clockIcon.getWidth()/2-35) * Math.sin((t.hour+(float)t.minute/60) * (Math.PI / 6) - Math.PI / 2)), p); //minute canvas.drawLine(X, Y,(int)(X + (clockIcon.getWidth()/2-27) * Math.cos(t.minute * (Math.PI / 30) - Math.PI / 2)),(int)(Y + (clockIcon.getWidth()/2-27) * Math.sin(t.minute * (Math.PI / 30) - Math.PI / 2)),p); //second p.setColor(Color.RED); p.setStrokeWidth(1); p.setStyle(Paint.Style.FILL); canvas.drawLine(X, Y,(int)(X + (clockIcon.getWidth()/2-20) * Math.cos(t.second * (Math.PI / 30) - Math.PI / 2)),(int)(Y + (clockIcon.getWidth()/2-20) * Math.sin(t.second * (Math.PI / 30) - Math.PI / 2)),p); p.setColor(Color.WHITE); canvas.drawCircle(X, Y, 4, p); p.setColor(Color.GRAY); canvas.drawCircle(X, Y, 2, p); }      class ClockThread extends Thread {          int times = 0;          boolean running = true;          public boolean wait = false;          public void stopRun() {              running = false;              synchronized (this) {                  this.notify();              }          };          public void pauseRun() {              this.wait = true;              synchronized (this) {                  this.notify();              }          }          public void resumeRun() {              this.wait = false;              synchronized (this) {                  this.notify();              }          }          public void run() {              while (running) {                  synchronized (mView) {                      mView.postInvalidate();                  }                  if(!mIsShowInScreen){                      pauseRun();                  }                  mIsShowInScreen = false;                  try {                      Thread.sleep(500);                  } catch (Exception e) {                      System.out.println(e);                  }                  synchronized (this) {                      if (wait) {                          try {                              wait();                          } catch (InterruptedException e) {                              // TODO Auto-generated catch block                              e.printStackTrace();                          }                      }                  }              }          }      }   }  

接下来就是如何初始化这个ClockScript,在Icon类里面添加代码

--- a/packages/apps/Launcher3/src/com/android/launcher3/IconCache.java +++ b/packages/apps/Launcher3/src/com/android/launcher3/IconCache.java @@ -84,6 +84,7 @@ public class IconCache {          public CharSequence title = "";          public CharSequence contentDescription = "";          public boolean isLowResIcon; +        public IconScript script;      }      private final HashMap<UserHandleCompat, Bitmap> mDefaultIcons = new HashMap<>(); @@ -591,7 +592,17 @@ public class IconCache {         if (info != null) {             entry.title = info.getLabel();         } - +       +       Log.e("IconCache ","componentName.getPackageName()="+componentName.getPackageName());         //加了一个系统的属性来控制 +       if(null != entry && componentName.getPackageName().equals("com.android.deskclock")  && android.os.SystemProperties.getBoolean("launcher.calender.updateicon", false)) +       {         +          Log.e("IconCache","clock init"); +           entry.script = new ClockScript(mContext);   +       }          return entry;      } @@ -891,4 +902,20 @@ public class IconCache {              return null;          }      } +    public IconScript getScript(Intent intent, UserHandleCompat user){   +        synchronized (mCache) {   +             ComponentName component = intent.getComponent();   +             +             if (component == null) {   +                Log.e("IconCache ","component==null"); +                 return null;   +             }   +            LauncherActivityInfoCompat launcherActInfo = mLauncherApps.resolveActivity(intent, user);   +            CacheEntry entry = cacheLocked(component, launcherActInfo,user, false, false);   +            return entry.script;   +        }   +    }  

在BubbleTextView类中添加代码

--- a/packages/apps/Launcher3/src/com/android/launcher3/BubbleTextView.java +++ b/packages/apps/Launcher3/src/com/android/launcher3/BubbleTextView.java @@ -30,6 +30,7 @@ import android.graphics.drawable.ColorDrawable;  import android.graphics.drawable.Drawable;  import android.os.Build;  import android.util.AttributeSet; +import android.util.Log;  import android.util.SparseArray;  import android.util.TypedValue;  import android.view.KeyEvent; @@ -38,6 +39,7 @@ import android.view.View;  import android.view.ViewConfiguration;  import android.view.ViewParent;  import android.widget.TextView; +import android.graphics.Rect;  import com.android.launcher3.IconCache.IconLoadRequest;  import com.android.launcher3.model.PackageItemInfo; @@ -148,12 +150,44 @@ public class BubbleTextView extends TextView      public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache) {          applyFromShortcutInfo(info, iconCache, false); -    } +         +        mScript = info.getScript(iconCache); //zengxiao add +        if(mScript!=null){ +        if(mScript!=null){ +        }else{ +               Log.e("rtyre","info.iconResource.packageName ------null"); +        } +    } +   private IconScript mScript; +    @Override   +    public void setCompoundDrawables(Drawable left, Drawable top,   +            Drawable right, Drawable bottom) {   +        +        if(top != null){   +              +            if(mScript != null){   +               +                top = mScript;   +                Rect rect=new Rect(0,0,LauncherAppState.getInstance().getInvariantDeviceProfile().iconBitmapSize,LauncherAppState.getInstanc +                mScript.setBounds(rect);   +                          +                if(!mScript.isRuning)  +                { +                             +                               mScript.run(this);   +                } +            }   +        }   +       +        super.setCompoundDrawables(left, top, right, bottom);   +    }        public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,              boolean promiseStateChanged) {          Bitmap b = info.getIcon(iconCache); - +        mScript = info.getScript(iconCache);           FastBitmapDrawable iconDrawable = mLauncher.createIconDrawable(b); --- a/packages/apps/Launcher3/src/com/android/launcher3/ShortcutInfo.java +++ b/packages/apps/Launcher3/src/com/android/launcher3/ShortcutInfo.java @@ -304,5 +304,13 @@ public class ShortcutInfo extends ItemInfo {      public boolean isDisabled() {          return isDisabled != 0;      } +     +     +    public IconScript getScript(IconCache iconCache){   +        return iconCache.getScript(promisedIntent != null ? promisedIntent : intent, user);   +    }   +      }

把这些代码添加上功能基本ok.

有了这个基础,我想要实现的效果就变得很简单,同样的定义一个WallpaperScript继承IconScript

package com.android.launcher3; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.text.format.Time; import android.view.View; import android.util.Log; import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.Paint; import java.util.Calendar; import android.graphics.BitmapFactory; import android.graphics.Matrix; public class WallpaperScript extends IconScript {       private float mDensity = 1.5f;       Time mTime = new Time();       int myCount =0;     Context mContext;      Boolean isDraw =false;      /**      * 效果展示目标View      */       private View mView;       /**      * 当前是否显示在屏幕上      */       private boolean mIsShowInScreen = false;          /**      * 通知系统更新视图现成      */       private WallpaperThread mWallpaperThread = null;       int[] arr=new int[]{R.drawable.ic_launcher_wallpaper_1,R.drawable.ic_launcher_wallpaper_2,R.drawable.ic_launcher_wallpaper_3,                         R.drawable.ic_launcher_wallpaper_4,R.drawable.ic_launcher_wallpaper_5,R.drawable.ic_launcher_wallpaper_6     };     int index = 0;     public WallpaperScript(Context context) {           super();           mContext = context;       }     public void run(View view) {          mView = view;          if(mWallpaperThread == null){            //Log.d("WallpaperScript","mWallpaperThread  ");                    mWallpaperThread = new WallpaperThread();              mWallpaperThread.start();          }          IntentFilter filter = new IntentFilter();            filter.addAction("android.intent.action.WallpaperChange");                          view.getContext().registerReceiver(new BroadcastReceiver() {                 @Override                 public void onReceive(Context arg0, Intent arg1) {                      Log.d("WallpaperScript","onReceive  ");                        isDraw = true;                    mWallpaperThread.startRun();                      mWallpaperThread.start();                   // myCount =0;               }            }, filter);              }      @Override      public void onPause() {          mWallpaperThread.pauseRun();          super.onPause();      }      @Override      public void onResume() {          mWallpaperThread.resumeRun();          super.onResume();      }      @Override      public void onStop() {          mWallpaperThread.stopRun();          super.onStop();      }       @Override       public void draw(Canvas canvas) {           super.draw(canvas);           Bitmap wallpaperIconfirst = Utilities.createIconBitmap( BitmapFactory.decodeResource(mContext.getResources(), arr[0]),mContext);           canvas.drawBitmap(wallpaperIconfirst, null, getBounds(),mPaint);//默认显示的图片          if(isDraw){             index = index%6;             Bitmap wallpaperIcon = Utilities.createIconBitmap( BitmapFactory.decodeResource(mContext.getResources(), arr[index]),mContext);               index = index+1;             myCount =myCount+1;             canvas.drawBitmap(wallpaperIcon, null, getBounds(),mPaint);//画底图               //Log.d("WallpaperScript","WallpaperScript index "+index+" myCount "+myCount);             if(myCount==49){                 myCount=0;                 mWallpaperThread.stopRun();                 //Log.d("WallpaperScript","WallpaperScript myCount " +myCount);                 isDraw = false;             }             }     }     class WallpaperThread extends Thread {          int times = 0;          boolean running = true;          public boolean wait = false;           public void startRun() {              running = true;              synchronized (this) {                  this.notify();              }         };          public void stopRun() {              running = false;              synchronized (this) {                  this.notify();              }         };          public void pauseRun() {              /*this.wait = true;              synchronized (this) {                  this.notify();              } */         }          public void resumeRun() {              /*this.wait = false;              synchronized (this) {                  this.notify();              }*/          }          public void run() {             Log.d("WallpaperScript","WallpaperThread running "+ running);                    while (running) {                  synchronized (mView) {                    Log.d("WallpaperScript","WallpaperThread run()");                                       mView.postInvalidate();                  }                  try {                      Thread.sleep(50);                  } catch (Exception e) {                      System.out.println(e);                  }              }          }      }   }  

把所有的图片放到一个数组里面,然后轮流去绘制里面的图片,点击图标的时候会发送一个广播,通过广播去控制线程的开启,这样功能基本上实现。

另外,怎样去实现没有界面的app,这个只需要AndroidManifest设置。

android:theme="@android:style/Theme.NoDisplay"

切换锁屏壁纸和主屏幕壁纸的代码

WallpaperManager manager = WallpaperManager.getInstance(this); try {     manager.setBitmap(bitmap,null, true, WallpaperManager.FLAG_LOCK | WallpaperManager.FLAG_SYSTEM); } catch (Exception e) {     e.printStackTrace(); }

推荐阅读