轉載請註明出處:http://blog.csdn.net/ruils/article/details/16922557
最近有人問我金山清理大師桌面上的一鍵加速的動畫是如何實現的,我下了個金山清理大師裝在手機上,體現了一把,感覺還不錯,所以就花了點時間研究了一下。
先看看效果:
點一下,
第一感覺就是在Window中增加View的做法來實現的,像360衛士的懸浮窗那樣,而且這個動畫效果會隨着一鍵加速圖標在桌面上的位置改變而改變,放在什麼地方就從什麼地方開始做動畫,放在左邊屏幕,就會向右邊做動畫,放在右邊屏幕會向左邊做動畫,在自己的代碼中怎麼才能知道自己的圖標所在屏幕的位置呢,百思不得其解,後來看了下Log,才發現其中的奧祕
Log:
I/ActivityManager(595): START u0 {act=android.intent.action.MAIN flg=0x10000000 cmp=com.cleanmaster.mguard_cn/com.cleanmaster.processcleaner.ProcessCleanerActivity bnds=[216,385][376,585]} from pid 866
從log中可以看出,點擊一鍵加速的圖標,實現上是啓動了一個activity,而且還帶有參數:bnds=[216,385][376,585],我去找了下Lanucher中的代碼,
packages/apps/Launcher2/src/com/android/launcher2/
Launcher.java
2001 Object tag = v.getTag();
2002 if (tag instanceof ShortcutInfo) {
2003 // Open shortcut
2004 final Intent intent = ((ShortcutInfo) tag).intent;
2005 int[] pos = new int[2];
2006 v.getLocationOnScreen(pos);
2007 intent.setSourceBounds(new Rect(pos[0], pos[1],
2008 pos[0] + v.getWidth(), pos[1] + v.getHeight()));
2009
2010 boolean success = startActivitySafely(v, intent, tag);
2011
2012 if (success && v instanceof BubbleTextView) {
2013 mWaitingForResume = (BubbleTextView) v;
2014 mWaitingForResume.setStayPressed(true);
2015 }
2016 } else if (tag instanceof FolderInfo) {
只有在點擊一個快捷方式的時候,纔會有附帶座標信息,原來這個一鍵加速是個快捷方式!現在明白了,點擊一個快捷方式圖標的時候,Lanucher會把此快捷方式的矩形的座標放在Intent中傳給所啓動的activity。
intent.setSourceBounds
既然知道這個座標是怎麼放的了,那取出來就簡單了:
intent.getSourceBounds();
那接下來就一步一步實現這個動畫
程序中用到的圖片資源,我是從金山清理大師的APK中拿出來的,僅供學習參考之用!
1.首先要添加一個快捷方式到桌面
請參考我寫的另外一篇博客:
2.創建這個快捷方式啓動的Activity.
這個activity得是透明的,我們創建一個Style
<style name="Transparent">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
</style>
然後把這個Style應用到這個Activity上:
<activity
android:name="com.cleanmanager.AnimationActivity"
android:theme="@style/Transparent" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
注意給Activity加上<action android:name="android.intent.action.MAIN" />,因爲這個Activity要從別的程序(Lanucher)中啓動,所以這個Activity要能夠做爲一個啓動的入口。
3. 在onCreate方法中,把動畫所需要的佈局文件顯示在快捷方式所在的位置:
// 取得Lanucher傳過來的所點擊的快捷方式的矩形座標。
rect = intent.getSourceBounds();
if (rect == null) {
finish();
return;
}
Log.d(TAG, rect.toShortString());
mRelativeLayout = (RelativeLayout) findViewById(R.id.framelayout);
mShortcut = (RelativeLayout) findViewById(R.id.shortcut);
backImageView = (ImageView) findViewById(R.id.clean_back);
roateImageView = (ImageView) findViewById(R.id.clean_rotate);
// iconmageView = (ImageView) findViewById(R.id.clean_icon);
textView = (TextView) findViewById(R.id.text);
// DisplayMetrics dm = new DisplayMetrics();
int width = getWindowManager().getDefaultDisplay().getWidth();
int hight = getWindowManager().getDefaultDisplay().getHeight();
Log.d(TAG, "width = " + width);
Log.d(TAG, "hight = " + hight);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mShortcut
.getLayoutParams();
layoutParams.topMargin = rect.top - (rect.bottom - rect.top) / 4;
// 判斷快捷方式在屏幕的哪一邊,如果在左邊,伸縮動畫就會向右,如果在右邊,伸縮動畫向左。
if (rect.left < width / 2) {
direction = Direction.RIGHT;
layoutParams.leftMargin = rect.left;
} else {
direction = Direction.LEFT;
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
layoutParams.rightMargin = width - rect.right;
Log.d(TAG, "rightMargin = " + (width - rect.right));
}
mRelativeLayout.updateViewLayout(mShortcut, layoutParams);
快捷方式在屏幕左邊的時候,就以左邊爲基準,快捷方式在屏幕右邊的時候,就以右邊爲基準。
4.在onAttachedToWindow的時候,開始做旋轉動畫。 我們模擬金山清理大師正在清理,兩秒鐘之後,清理完了,開始做伸縮了
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
// 旋轉動畫開始
roateImageView.startAnimation(AnimationUtils.loadAnimation(this,
R.anim.rotate_anim));
// 假設垃圾清理了兩秒鐘,然後開如做伸縮動畫。
mHandler.sendEmptyMessageDelayed(MESSAGE_ROTATE_FINISHED, 2000);
}
5.把旋轉動畫清除,然後開始拉伸updateWidth();
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MESSAGE_ROTATE_FINISHED:
mWidth = backImageView.getWidth();
Log.d(TAG, "mWidth = " + mWidth);
updateWidth();
roateImageView.clearAnimation();
roateImageView.setVisibility(View.INVISIBLE);
break;
case MESSAGE_UPDATE_WIDTH:
updateWidth();
break;
default:
break;
}
};
6.主要是通過不停的加大拉伸ImageView的寬度來實現拉伸動畫。實現方式有很多種,可以自定義View,以後我會講解如何自定義View,這裏用的比較簡單的方式實現的。
定義寬度到達以前寬度的2.5倍就線束動畫,顯示文字。
private void updateWidth() {
// 寬度沒有達到原來寬度的2.5度,繼續做動畫
if (backImageView.getWidth() <= 2.5f * mWidth) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) backImageView
.getLayoutParams();
// 每次增加20的寬度,可以自行設置,和用戶體驗有關係,可自行調整
layoutParams.width = backImageView.getWidth() + 20;
mShortcut.updateViewLayout(backImageView, layoutParams);
// 繼續發更新消息。也可發送delay消息,和用戶體驗有關係,<span style="font-family: Arial, Helvetica, sans-serif;">可自行調整</span>
mHandler.sendEmptyMessage(MESSAGE_UPDATE_WIDTH);
} else {
textView.setVisibility(View.VISIBLE);
}
};
看下效果:
點一下,
如果您喜歡這篇文章請點贊哦!
最後附上源碼:
示例源碼下載:http://download.csdn.net/detail/u012379847/6604299
Github地址:https://github.com/seashell752/CleanManager