本文实例为大家分享了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();
}