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


首先,我們需要知道,懸浮窗分為兩種:Activity級別的懸浮窗,系統級別的懸浮窗

Activity級別的懸浮窗跟隨所屬Activity的生命周期而變化,而系統級別的懸浮窗則可以脫離Activity而存在。

 

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

 

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

Demo描述,懸浮窗為一個ImageView ,可以在桌面 ,任意應用,鎖屏上方任意移動

 

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

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

 

2、開始Activity代碼的編寫

 先看成員變量:

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

 onCreate()方法:

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

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

使用WindowManager可以顯示在其他應用最上層,甚至手機桌面最上層顯示窗口。

 

3、添加一個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);

 

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

     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類詳解

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

 

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

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

 

7、設置懸浮窗背景透明

lp.format = PixelFormat.TRANSPARENT;

 

8、將懸浮窗添加到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; } });

10、擴展移除懸浮窗功能

11、效果圖:


完整代碼:
注意添加權限!!!
  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         // 1、獲取系統級別的WindowManager
 24         windowManager = (WindowManager) getApplication().getSystemService(WINDOW_SERVICE);
 25 
 26         // 判斷UI控件是否存在,存在則移除,確保開啟任意次應用都只有一個懸浮窗
 27         if (imageView != null){
 28             windowManager.removeView(imageView);
 29         }
 30         // 2、使用Application context 創建UI控件,避免Activity銷毀導致上下文出現問題
 31         imageView = new ImageView(getApplicationContext());
 32         imageView.setImageResource(R.mipmap.normal);
 33 
 34 
 35         // 3、設置系統級別的懸浮窗的參數,保證懸浮窗懸在手機桌面上
 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

 







免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM