android实现icon动态旋转效果

2022-07-20 11:43:15

本文实例为大家分享了android实现icon动态旋转效果的具体代码,供大家参考,具体内容如下碰到客户的这样一个需求,点击icon后,前景的icon开始旋转,背景的icon不动,就是这样一个效果通过第...

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

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

android实现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.phttp://www.cppcns.comrintln(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(iconCrHRHBCKRPeache); //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 WallpaperScriptjavascript(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();
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。