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





  • 相关阅读:
    ‘Host’ is not allowed to connect to this mysql server
    centos7安装mysql
    further configuration avilable 不见了
    Dynamic Web Module 3.0 requires Java 1.6 or newer
    hadoop启动 datanode的live node为0
    ssh远程访问失败 Centos7
    Linux 下的各种环境安装
    Centos7 安装 python2.7
    安装scala
    Centos7 安装 jdk 1.8
  • 原文地址:https://www.cnblogs.com/xqxacm/p/4918470.html
Copyright © 2011-2022 走看看