生活随笔
收集整理的這篇文章主要介紹了
Android桌面悬浮窗进阶,QQ手机管家小火箭效果实现
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
這次我們將代碼的重點(diǎn)放在火箭升空的效果上,因此簡(jiǎn)單起見(jiàn),就直接在模仿360手機(jī)衛(wèi)士懸浮窗的那份代碼的基礎(chǔ)上繼續(xù)開(kāi)發(fā)了,如果你還沒(méi)有看過(guò)那篇文章的話,建議先去閱讀?Android桌面懸浮窗效果實(shí)現(xiàn),仿360手機(jī)衛(wèi)士懸浮窗效果?。
比起普通的桌面懸浮窗,現(xiàn)在我們需要在拖動(dòng)懸浮窗的時(shí)候?qū)腋〈白兂梢粋€(gè)小火箭,并且在屏幕的底部添加一個(gè)火箭發(fā)射臺(tái)。那么我們就從火箭發(fā)射臺(tái)開(kāi)始編寫(xiě)吧,首先創(chuàng)建launcher.xml作為火箭發(fā)射臺(tái)的布局文件,如下所示:
[html]?view plaincopy
<?xml?version="1.0"?encoding="UTF-8"?>?? <LinearLayout?? ????xmlns:android="http://schemas.android.com/apk/res/android"?? ????android:layout_width="wrap_content"?? ????android:layout_height="wrap_content"?? ????android:orientation="vertical"?? ????>?? ?????? ????<ImageView??? ????????android:id="@+id/launcher_img"?? ????????android:layout_width="200dp"?? ????????android:layout_height="88dp"?? ????????android:src="@drawable/launcher_bg_hold"?? ????????/>?? ?????? </LinearLayout>??
可以看到,這里的ImageView是用于顯示當(dāng)前火箭發(fā)射臺(tái)狀態(tài)的。我事先準(zhǔn)備好了兩張圖片,一張是當(dāng)小火箭未拖動(dòng)到火箭發(fā)射臺(tái)時(shí)顯示的,一張是當(dāng)小火箭拖動(dòng)到火箭發(fā)射臺(tái)上時(shí)顯示的。
接下來(lái)創(chuàng)建RocketLauncher類,作為火箭發(fā)射臺(tái)的View,代碼如下所示:
[java] view plaincopy
public?class?RocketLauncher?extends?LinearLayout?{????????????????public?static?int?width;????????????????public?static?int?height;????????????????private?ImageView?launcherImg;????????public?RocketLauncher(Context?context)?{??????????super(context);??????????LayoutInflater.from(context).inflate(R.layout.launcher,?this);??????????launcherImg?=?(ImageView)?findViewById(R.id.launcher_img);??????????width?=?launcherImg.getLayoutParams().width;??????????height?=?launcherImg.getLayoutParams().height;??????}????????????????public?void?updateLauncherStatus(boolean?isReadyToLaunch)?{??????????if?(isReadyToLaunch)?{??????????????launcherImg.setImageResource(R.drawable.launcher_bg_fire);??????????}?else?{??????????????launcherImg.setImageResource(R.drawable.launcher_bg_hold);??????????}??????}????}??
RocketLauncher中的代碼還是非常簡(jiǎn)單的,在構(gòu)建方法中調(diào)用了LayoutInflater的inflate()方法來(lái)將launcher.xml這個(gè)布局文件加載進(jìn)來(lái),并獲取到了當(dāng)前View的寬度和高度。在updateLauncherStatus()方法中會(huì)進(jìn)行判斷,如果傳入的參數(shù)是true,就顯示小火箭即將發(fā)射的圖片,如果傳入的是false,就顯示將小火箭拖動(dòng)到發(fā)射臺(tái)的圖片。
新增的文件只有這兩個(gè),剩下的就是要修改之前的代碼了。首先修改MyWindowManager中的代碼,如下所示:
[java] view plaincopy
public?class?MyWindowManager?{????????????????private?static?FloatWindowSmallView?smallWindow;????????????????private?static?FloatWindowBigView?bigWindow;????????????????private?static?RocketLauncher?rocketLauncher;????????????????private?static?LayoutParams?smallWindowParams;????????????????private?static?LayoutParams?bigWindowParams;????????????????private?static?LayoutParams?launcherParams;????????????????private?static?WindowManager?mWindowManager;????????????????private?static?ActivityManager?mActivityManager;????????????????public?static?void?createSmallWindow(Context?context)?{??????????WindowManager?windowManager?=?getWindowManager(context);??????????int?screenWidth?=?windowManager.getDefaultDisplay().getWidth();??????????int?screenHeight?=?windowManager.getDefaultDisplay().getHeight();??????????if?(smallWindow?==?null)?{??????????????smallWindow?=?new?FloatWindowSmallView(context);??????????????if?(smallWindowParams?==?null)?{??????????????????smallWindowParams?=?new?LayoutParams();??????????????????smallWindowParams.type?=?LayoutParams.TYPE_SYSTEM_ALERT;??????????????????smallWindowParams.format?=?PixelFormat.RGBA_8888;??????????????????smallWindowParams.flags?=?LayoutParams.FLAG_NOT_TOUCH_MODAL??????????????????????????|?LayoutParams.FLAG_NOT_FOCUSABLE;??????????????????smallWindowParams.gravity?=?Gravity.LEFT?|?Gravity.TOP;??????????????????smallWindowParams.width?=?FloatWindowSmallView.windowViewWidth;??????????????????smallWindowParams.height?=?FloatWindowSmallView.windowViewHeight;??????????????????smallWindowParams.x?=?screenWidth;??????????????????smallWindowParams.y?=?screenHeight?/?2;??????????????}??????????????smallWindow.setParams(smallWindowParams);??????????????windowManager.addView(smallWindow,?smallWindowParams);??????????}??????}????????????????public?static?void?removeSmallWindow(Context?context)?{??????????if?(smallWindow?!=?null)?{??????????????WindowManager?windowManager?=?getWindowManager(context);??????????????windowManager.removeView(smallWindow);??????????????smallWindow?=?null;??????????}??????}????????????????public?static?void?createBigWindow(Context?context)?{??????????WindowManager?windowManager?=?getWindowManager(context);??????????int?screenWidth?=?windowManager.getDefaultDisplay().getWidth();??????????int?screenHeight?=?windowManager.getDefaultDisplay().getHeight();??????????if?(bigWindow?==?null)?{??????????????bigWindow?=?new?FloatWindowBigView(context);??????????????if?(bigWindowParams?==?null)?{??????????????????bigWindowParams?=?new?LayoutParams();??????????????????bigWindowParams.x?=?screenWidth?/?2??????????????????????????-?FloatWindowBigView.viewWidth?/?2;??????????????????bigWindowParams.y?=?screenHeight?/?2??????????????????????????-?FloatWindowBigView.viewHeight?/?2;??????????????????bigWindowParams.type?=?LayoutParams.TYPE_PHONE;??????????????????bigWindowParams.format?=?PixelFormat.RGBA_8888;??????????????????bigWindowParams.gravity?=?Gravity.LEFT?|?Gravity.TOP;??????????????????bigWindowParams.width?=?FloatWindowBigView.viewWidth;??????????????????bigWindowParams.height?=?FloatWindowBigView.viewHeight;??????????????}??????????????windowManager.addView(bigWindow,?bigWindowParams);??????????}??????}????????????????public?static?void?removeBigWindow(Context?context)?{??????????if?(bigWindow?!=?null)?{??????????????WindowManager?windowManager?=?getWindowManager(context);??????????????windowManager.removeView(bigWindow);??????????????bigWindow?=?null;??????????}??????}????????????????public?static?void?createLauncher(Context?context)?{??????????WindowManager?windowManager?=?getWindowManager(context);??????????int?screenWidth?=?windowManager.getDefaultDisplay().getWidth();??????????int?screenHeight?=?windowManager.getDefaultDisplay().getHeight();??????????if?(rocketLauncher?==?null)?{??????????????rocketLauncher?=?new?RocketLauncher(context);??????????????if?(launcherParams?==?null)?{??????????????????launcherParams?=?new?LayoutParams();??????????????????launcherParams.x?=?screenWidth?/?2?-?RocketLauncher.width?/?2;??????????????????launcherParams.y?=?screenHeight?-?RocketLauncher.height;??????????????????launcherParams.type?=?LayoutParams.TYPE_PHONE;??????????????????launcherParams.format?=?PixelFormat.RGBA_8888;??????????????????launcherParams.gravity?=?Gravity.LEFT?|?Gravity.TOP;??????????????????launcherParams.width?=?RocketLauncher.width;??????????????????launcherParams.height?=?RocketLauncher.height;??????????????}??????????????windowManager.addView(rocketLauncher,?launcherParams);??????????}??????}????????????????public?static?void?removeLauncher(Context?context)?{??????????if?(rocketLauncher?!=?null)?{??????????????WindowManager?windowManager?=?getWindowManager(context);??????????????windowManager.removeView(rocketLauncher);??????????????rocketLauncher?=?null;??????????}??????}????????????????public?static?void?updateLauncher()?{??????????if?(rocketLauncher?!=?null)?{??????????????rocketLauncher.updateLauncherStatus(isReadyToLaunch());??????????}??????}???????????????????public?static?void?updateUsedPercent(Context?context)?{??????????if?(smallWindow?!=?null)?{??????????????TextView?percentView?=?(TextView)?smallWindow??????????????????????.findViewById(R.id.percent);??????????????percentView.setText(getUsedPercentValue(context));??????????}??????}??????????????????public?static?boolean?isWindowShowing()?{??????????return?smallWindow?!=?null?||?bigWindow?!=?null;??????}??????????????????public?static?boolean?isReadyToLaunch()?{??????????if?((smallWindowParams.x?>?launcherParams.x?&&?smallWindowParams.x??????????????????+?smallWindowParams.width?<?launcherParams.x??????????????????+?launcherParams.width)??????????????????&&?(smallWindowParams.y?+?smallWindowParams.height?>?launcherParams.y))?{??????????????return?true;??????????}??????????return?false;??????}????????????????????private?static?WindowManager?getWindowManager(Context?context)?{??????????if?(mWindowManager?==?null)?{??????????????mWindowManager?=?(WindowManager)?context??????????????????????.getSystemService(Context.WINDOW_SERVICE);??????????}??????????return?mWindowManager;??????}????????????????????private?static?ActivityManager?getActivityManager(Context?context)?{??????????if?(mActivityManager?==?null)?{??????????????mActivityManager?=?(ActivityManager)?context??????????????????????.getSystemService(Context.ACTIVITY_SERVICE);??????????}??????????return?mActivityManager;??????}????????????????????public?static?String?getUsedPercentValue(Context?context)?{??????????String?dir?=?"/proc/meminfo";??????????try?{??????????????FileReader?fr?=?new?FileReader(dir);??????????????BufferedReader?br?=?new?BufferedReader(fr,?2048);??????????????String?memoryLine?=?br.readLine();??????????????String?subMemoryLine?=?memoryLine.substring(memoryLine??????????????????????.indexOf("MemTotal:"));??????????????br.close();??????????????long?totalMemorySize?=?Integer.parseInt(subMemoryLine.replaceAll(??????????????????????"\\D+",?""));??????????????long?availableSize?=?getAvailableMemory(context)?/?1024;??????????????int?percent?=?(int)?((totalMemorySize?-?availableSize)??????????????????????/?(float)?totalMemorySize?*?100);??????????????return?percent?+?"%";??????????}?catch?(IOException?e)?{??????????????e.printStackTrace();??????????}??????????return?"懸浮窗";??????}????????????????????private?static?long?getAvailableMemory(Context?context)?{??????????ActivityManager.MemoryInfo?mi?=?new?ActivityManager.MemoryInfo();??????????getActivityManager(context).getMemoryInfo(mi);??????????return?mi.availMem;??????}????}??
MyWindowManager是所有桌面懸浮窗的管理器,這里我們主要添加了createLauncher()、removeLauncher()和updateLauncher()這幾個(gè)方法,分別用于創(chuàng)建、移除、以及更新火箭發(fā)射臺(tái)懸浮窗。另外還添加了isReadyToLaunch()這個(gè)方法,它是用于判斷小火箭是否已經(jīng)拖動(dòng)到火箭發(fā)射臺(tái)上了。判斷的方式當(dāng)然也很簡(jiǎn)單,只需要對(duì)小火箭的邊界和火箭發(fā)射臺(tái)的邊界進(jìn)行檢測(cè),判斷它們是否相交就行了。
接下來(lái)還需要修改FloatWindowSmallView中的代碼,當(dāng)手指拖動(dòng)懸浮窗的時(shí)候要將它變成小火箭,如下所示:
[java] view plaincopy
public?class?FloatWindowSmallView?extends?LinearLayout?{????????????????public?static?int?windowViewWidth;????????????????public?static?int?windowViewHeight;????????????????private?static?int?statusBarHeight;????????????????private?WindowManager?windowManager;????????????????private?LinearLayout?smallWindowLayout;????????????????private?ImageView?rocketImg;????????????????private?WindowManager.LayoutParams?mParams;????????????????private?float?xInScreen;????????????????private?float?yInScreen;????????????????private?float?xDownInScreen;????????????????private?float?yDownInScreen;????????????????private?float?xInView;????????????????private?float?yInView;????????????????private?int?rocketWidth;????????????????private?int?rocketHeight;????????????????private?boolean?isPressed;????????public?FloatWindowSmallView(Context?context)?{??????????super(context);??????????windowManager?=?(WindowManager)?context??????????????????.getSystemService(Context.WINDOW_SERVICE);??????????LayoutInflater.from(context).inflate(R.layout.float_window_small,?this);??????????smallWindowLayout?=?(LinearLayout)?findViewById(R.id.small_window_layout);??????????windowViewWidth?=?smallWindowLayout.getLayoutParams().width;??????????windowViewHeight?=?smallWindowLayout.getLayoutParams().height;??????????rocketImg?=?(ImageView)?findViewById(R.id.rocket_img);??????????rocketWidth?=?rocketImg.getLayoutParams().width;??????????rocketHeight?=?rocketImg.getLayoutParams().height;??????????TextView?percentView?=?(TextView)?findViewById(R.id.percent);??????????percentView.setText(MyWindowManager.getUsedPercentValue(context));??????}????????@Override??????public?boolean?onTouchEvent(MotionEvent?event)?{??????????switch?(event.getAction())?{??????????case?MotionEvent.ACTION_DOWN:??????????????isPressed?=?true;????????????????????????????xInView?=?event.getX();??????????????yInView?=?event.getY();??????????????xDownInScreen?=?event.getRawX();??????????????yDownInScreen?=?event.getRawY()?-?getStatusBarHeight();??????????????xInScreen?=?event.getRawX();??????????????yInScreen?=?event.getRawY()?-?getStatusBarHeight();??????????????break;??????????case?MotionEvent.ACTION_MOVE:??????????????xInScreen?=?event.getRawX();??????????????yInScreen?=?event.getRawY()?-?getStatusBarHeight();????????????????????????????updateViewStatus();??????????????updateViewPosition();??????????????break;??????????case?MotionEvent.ACTION_UP:??????????????isPressed?=?false;??????????????if?(MyWindowManager.isReadyToLaunch())?{??????????????????launchRocket();??????????????}?else?{??????????????????updateViewStatus();????????????????????????????????????if?(xDownInScreen?==?xInScreen?&&?yDownInScreen?==?yInScreen)?{??????????????????????openBigWindow();??????????????????}??????????????}??????????????break;??????????default:??????????????break;??????????}??????????return?true;??????}???????????????????public?void?setParams(WindowManager.LayoutParams?params)?{??????????mParams?=?params;??????}????????????????private?void?launchRocket()?{??????????MyWindowManager.removeLauncher(getContext());??????????new?LaunchTask().execute();??????}????????????????private?void?updateViewPosition()?{??????????mParams.x?=?(int)?(xInScreen?-?xInView);??????????mParams.y?=?(int)?(yInScreen?-?yInView);??????????windowManager.updateViewLayout(this,?mParams);??????????MyWindowManager.updateLauncher();??????}????????????????private?void?updateViewStatus()?{??????????if?(isPressed?&&?rocketImg.getVisibility()?!=?View.VISIBLE)?{??????????????mParams.width?=?rocketWidth;??????????????mParams.height?=?rocketHeight;??????????????windowManager.updateViewLayout(this,?mParams);??????????????smallWindowLayout.setVisibility(View.GONE);??????????????rocketImg.setVisibility(View.VISIBLE);??????????????MyWindowManager.createLauncher(getContext());??????????}?else?if?(!isPressed)?{??????????????mParams.width?=?windowViewWidth;??????????????mParams.height?=?windowViewHeight;??????????????windowManager.updateViewLayout(this,?mParams);??????????????smallWindowLayout.setVisibility(View.VISIBLE);??????????????rocketImg.setVisibility(View.GONE);??????????????MyWindowManager.removeLauncher(getContext());??????????}??????}????????????????private?void?openBigWindow()?{??????????MyWindowManager.createBigWindow(getContext());??????????MyWindowManager.removeSmallWindow(getContext());??????}??????????????????private?int?getStatusBarHeight()?{??????????if?(statusBarHeight?==?0)?{??????????????try?{??????????????????Class<?>?c?=?Class.forName("com.android.internal.R$dimen");??????????????????Object?o?=?c.newInstance();??????????????????Field?field?=?c.getField("status_bar_height");??????????????????int?x?=?(Integer)?field.get(o);??????????????????statusBarHeight?=?getResources().getDimensionPixelSize(x);??????????????}?catch?(Exception?e)?{??????????????????e.printStackTrace();??????????????}??????????}??????????return?statusBarHeight;??????}??????????????????class?LaunchTask?extends?AsyncTask<Void,?Void,?Void>?{????????????@Override??????????protected?Void?doInBackground(Void...?params)?{????????????????????????????while?(mParams.y?>?0)?{??????????????????mParams.y?=?mParams.y?-?10;??????????????????publishProgress();??????????????????try?{??????????????????????Thread.sleep(8);??????????????????}?catch?(InterruptedException?e)?{??????????????????????e.printStackTrace();??????????????????}??????????????}??????????????return?null;??????????}????????????@Override??????????protected?void?onProgressUpdate(Void...?values)?{??????????????windowManager.updateViewLayout(FloatWindowSmallView.this,?mParams);??????????}????????????@Override??????????protected?void?onPostExecute(Void?result)?{????????????????????????????updateViewStatus();??????????????mParams.x?=?(int)?(xDownInScreen?-?xInView);??????????????mParams.y?=?(int)?(yDownInScreen?-?yInView);??????????????windowManager.updateViewLayout(FloatWindowSmallView.this,?mParams);??????????}????????}????}??
這里在代碼中添加了一個(gè)isPressed標(biāo)識(shí)位,用于判斷用戶是否正在拖動(dòng)懸浮窗。當(dāng)拖動(dòng)的時(shí)候就調(diào)用updateViewStatus()方法來(lái)更新懸浮窗的顯示狀態(tài),這時(shí)懸浮窗就會(huì)變成一個(gè)小火箭。然后當(dāng)手指離開(kāi)屏幕的時(shí)候,也會(huì)調(diào)用updateViewStatus()方法,這時(shí)發(fā)現(xiàn)isPressed為false,就會(huì)將懸浮窗重新顯示出來(lái)。
同時(shí),當(dāng)手指離開(kāi)屏幕的時(shí)候,還會(huì)調(diào)用MyWindowManager的isReadyToLaunch()方法來(lái)判斷小火箭是否被拖動(dòng)到火箭發(fā)射臺(tái)上了,如果為true,就會(huì)觸發(fā)火箭升空的動(dòng)畫(huà)效果。火箭升空的動(dòng)畫(huà)實(shí)現(xiàn)是寫(xiě)在LaunchTask這個(gè)任務(wù)里的,可以看到,這里會(huì)在doInBackground()方法中執(zhí)行耗時(shí)邏輯,將小火箭的縱坐標(biāo)不斷減小,以讓它實(shí)現(xiàn)上升的效果。當(dāng)縱坐標(biāo)減小到0的時(shí)候,火箭升空的動(dòng)畫(huà)就結(jié)束了,然后在onPostExecute()方法中重新將懸浮窗顯示出來(lái)。
另外,在AndroidManifest.xml文件中記得要聲明兩個(gè)權(quán)限,如下所示:
[html]?view plaincopy
<uses-permission?android:name="android.permission.SYSTEM_ALERT_WINDOW"?/>?? <uses-permission?android:name="android.permission.GET_TASKS"?/>??
代碼就只有這么多,接下來(lái)我們運(yùn)行一下看看效果吧。在主界面點(diǎn)擊Start Float Window按鈕可以開(kāi)啟懸浮窗并回到桌面,然后拖動(dòng)懸浮窗后就會(huì)變成小火箭的狀態(tài),將它拖動(dòng)到屏幕底部火箭發(fā)射臺(tái)上,然后放手,小火箭就會(huì)騰空而起了,如下圖所示:
下載:http://download.csdn.net/detail/sinyu890807/6786059
總結(jié)
以上是生活随笔為你收集整理的Android桌面悬浮窗进阶,QQ手机管家小火箭效果实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。