zoukankan      html  css  js  c++  java
  • 简易的可拖动的桌面悬浮窗效果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





  • 相关阅读:
    Step one : 熟悉Unix/Linux Shell 常见命令行 (三)
    Step one : 熟悉Unix/Linux Shell 常见命令行 (一)
    PLAN: step one
    PLAN : 入门题目 ( update )
    SZU : A11 Sequence
    SZU:B85 Alec's Eggs
    codeforces 518B. Tanya and Postcard 解题报告
    BestCoder8 1001.Summary(hdu 4989) 解题报告
    hdu 1556.Color the ball 解题报告
    codeforces 515C. Drazil and Factorial 解题报告
  • 原文地址:https://www.cnblogs.com/xqxacm/p/4918470.html
Copyright © 2011-2022 走看看