簡易的可拖動的桌面懸浮窗效果Demo

首先,咱們須要知道,懸浮窗分爲兩種:Activity級別的懸浮窗,系統級別的懸浮窗java

Activity級別的懸浮窗跟隨所屬Activity的生命週期而變化,而系統級別的懸浮窗則能夠脫離Activity而存在。android

 

由此可知,要實現360手機衛士那樣的懸浮窗效果,就須要使用系統級別的懸浮窗app

 

下面學習實現桌面懸浮窗效果的代碼步驟:ide

Demo描述,懸浮窗爲一個ImageView ,能夠在桌面 ,任意應用,鎖屏上方任意移動學習

 

一、配置清單文件AndroidManifest.xml 中 添加系統懸浮窗的權限spa

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

 

二、開始Activity代碼的編寫.net

 先當作員變量:code

 private WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); private static WindowManager windowManager; private static ImageView imageView;

 onCreate()方法:orm

獲取WindwoManager對象,該對象是系統級別的xml

windowManager = (WindowManager) getApplication().getSystemService(WINDOW_SERVICE);

使用WindowManager能夠顯示在其餘應用最上層,甚至手機桌面最上層顯示窗口。

 

三、添加一個UI空間,做爲懸浮窗的內容 ,固然Demo是一個ImageView做爲懸浮窗內容,實際項目中就須要用複雜View,ViewGroup來擴展功能了

     
     //注意,懸浮窗只有一個,而當打開應用的時候纔會產生懸浮窗,因此要判斷懸浮窗是否已經存在,
     if
(imageView != null){ windowManager.removeView(imageView); } // 使用Application context 建立UI控件,避免Activity銷燬致使上下文出現問題,由於如今的懸浮窗是系統級別的,不依賴與Activity存在    imageView = new ImageView(getApplicationContext()); imageView.setImageResource(R.mipmap.normal);

 

四、設置系統級別的懸浮窗的參數,保證懸浮窗懸在手機桌面上

     lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT |WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
//TYPE_SYSTEM_ALERT  系統提示,它老是出如今應用程序窗口之上
//TYPE_SYSTEM_OVERLAY 系統頂層窗口。顯示在其餘一切內容之上。此窗口不能得到輸入焦點,不然影響鎖屏
// FLAG_NOT_FOCUSABLE 懸浮窗口較小時,後面的應用圖標由不可長按變爲可長按,不設置這個flag的話,home頁的劃屏會有問題
// FLAG_NOT_TOUCH_MODAL不阻塞事件傳遞到後面的窗口

關於 WindowManager.LayoutParams 的詳解 請參考:Android中WindowManager.LayoutParams類詳解

五、懸浮窗默認顯示的位置
 lp.gravity = Gravity.LEFT|Gravity.TOP;  //顯示在屏幕左上角

 

六、懸浮窗相對5默認位置的位置差和懸浮窗寬高設置

     //顯示位置與指定位置的相對位置差
        lp.x = 0; lp.y = 0; //懸浮窗的寬高
        lp.width = WindowManager.LayoutParams.WRAP_CONTENT; lp.height = WindowManager.LayoutParams.WRAP_CONTENT;

 

七、設置懸浮窗背景透明

lp.format = PixelFormat.TRANSPARENT;

 

八、將懸浮窗添加到WindowManager對象中

 windowManager.addView(imageView,lp);

 

9.設置懸浮窗的響應事件

 這裏爲移動懸浮窗操做,能夠本身擴展添加點擊等響應事件

imageView.setOnTouchListener(new View.OnTouchListener() { private float lastX; //上一次位置的X.Y座標
            private float lastY; private float nowX;  //當前移動位置的X.Y座標
            private float nowY; private float tranX; //懸浮窗移動位置的相對值
            private float tranY; @Override public boolean onTouch(View v, MotionEvent event) { boolean ret = false; switch (event.getAction()){ case MotionEvent.ACTION_DOWN: // 獲取按下時的X,Y座標
                        lastX = event.getRawX(); lastY = event.getRawY(); ret = true; break; case MotionEvent.ACTION_MOVE: // 獲取移動時的X,Y座標
                        nowX = event.getRawX(); nowY = event.getRawY(); // 計算XY座標偏移量
                        tranX = nowX - lastX; tranY = nowY - lastY; // 移動懸浮窗
                        lp.x += tranX; lp.y += tranY; //更新懸浮窗位置
 windowManager.updateViewLayout(imageView,lp); //記錄當前座標做爲下一次計算的上一次移動的位置座標
                        lastX = nowX; lastY = nowY; break; case MotionEvent.ACTION_UP: break; } return ret; } });

十、擴展移除懸浮窗功能

十一、效果圖:


完整代碼:
注意添加權限!!!
  1 package com.xqx.window.app;
  2 
  3 import android.app.Activity;
  4 import android.graphics.PixelFormat;
  5 import android.os.Bundle;
  6 import android.view.*;
  7 import android.widget.ImageView;
  8 
  9 /**
 10  * 系統級別懸浮窗,能夠在手機桌面上顯示的懸浮窗
 11  */
 12 public class FloatWindowActivity extends Activity {
 13 
 14     private WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
 15     private static WindowManager windowManager;
 16     private static ImageView imageView;
 17 
 18     @Override
 19     protected void onCreate(Bundle savedInstanceState) {
 20         super.onCreate(savedInstanceState);
 21         setContentView(R.layout.activity_float_window);
 22 
 23         // 一、獲取系統級別的WindowManager
 24         windowManager = (WindowManager) getApplication().getSystemService(WINDOW_SERVICE);
 25 
 26         // 判斷UI控件是否存在,存在則移除,確保開啓任意次應用都只有一個懸浮窗
 27         if (imageView != null){
 28             windowManager.removeView(imageView);
 29         }
 30         // 二、使用Application context 建立UI控件,避免Activity銷燬致使上下文出現問題
 31         imageView = new ImageView(getApplicationContext());
 32         imageView.setImageResource(R.mipmap.normal);
 33 
 34 
 35         // 三、設置系統級別的懸浮窗的參數,保證懸浮窗懸在手機桌面上
 36         // 系統級別須要指定type 屬性
 37         // TYPE_SYSTEM_ALERT 容許接收事件
 38         // TYPE_SYSTEM_OVERLAY 懸浮在系統上
 39         // 注意清單文件添加權限
 40 
 41         //系統提示。它老是出如今應用程序窗口之上。
 42         lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
 43                   |WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
 44 
 45         // FLAG_NOT_TOUCH_MODAL不阻塞事件傳遞到後面的窗口
 46         // FLAG_NOT_FOCUSABLE 懸浮窗口較小時,後面的應用圖標由不可長按變爲可長按,不設置這個flag的話,home頁的劃屏會有問題
 47         lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
 48                   |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
 49 
 50         //懸浮窗默認顯示的位置
 51         lp.gravity = Gravity.LEFT|Gravity.TOP;
 52         //顯示位置與指定位置的相對位置差
 53         lp.x = 0;
 54         lp.y = 0;
 55         //懸浮窗的寬高
 56         lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
 57         lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
 58 
 59         lp.format = PixelFormat.TRANSPARENT;
 60         windowManager.addView(imageView,lp);
 61 
 62         //設置懸浮窗監聽事件
 63         imageView.setOnTouchListener(new View.OnTouchListener() {
 64             private float lastX; //上一次位置的X.Y座標
 65             private float lastY;
 66             private float nowX;  //當前移動位置的X.Y座標
 67             private float nowY;
 68             private float tranX; //懸浮窗移動位置的相對值
 69             private float tranY;
 70 
 71             @Override
 72             public boolean onTouch(View v, MotionEvent event) {
 73                 boolean ret = false;
 74                 switch (event.getAction()){
 75                     case MotionEvent.ACTION_DOWN:
 76                         // 獲取按下時的X,Y座標
 77                         lastX = event.getRawX();
 78                         lastY = event.getRawY();
 79                         ret = true;
 80                         break;
 81                     case MotionEvent.ACTION_MOVE:
 82                         // 獲取移動時的X,Y座標
 83                         nowX = event.getRawX();
 84                         nowY = event.getRawY();
 85                         // 計算XY座標偏移量
 86                         tranX = nowX - lastX;
 87                         tranY = nowY - lastY;
 88                         // 移動懸浮窗
 89                         lp.x += tranX;
 90                         lp.y += tranY;
 91                         //更新懸浮窗位置
 92                         windowManager.updateViewLayout(imageView,lp);
 93                         //記錄當前座標做爲下一次計算的上一次移動的位置座標
 94                         lastX = nowX;
 95                         lastY = nowY;
 96                         break;
 97                     case MotionEvent.ACTION_UP:
 98                         break;
 99                 }
100                 return ret;
101             }
102         });
103     }
104 
105 }
FloatWindowActivity.java
相關文章
相關標籤/搜索