不依赖于Activity的Android全局悬浮窗的实现_Android

前言

当我们在手机上使用360安全卫士时,手机屏幕上时刻都会出现一个小浮动窗口,点击该浮动窗口可跳转到安全卫士的操作界面,而且该浮动窗口不受其他activity的覆盖影响仍然可见(多米音乐也有相关的和主界面交互的悬浮小窗口)。那么这种不受Activity界面影响的悬浮窗口是怎么实现的呢?

Android悬浮窗实现

实现基础

Android悬浮窗实现使用WindowManager
WindowManager介绍  
通过Context.getSystemService(Context.WINDOW_SERVICE)可以获得 WindowManager对象。

每一个WindowManager对象都和一个特定的 Display绑定。

想要获取一个不同的display的WindowManager,可以用 createDisplayContext(Display)来获取那个displayContext,之后再使用:Context.getSystemService(Context.WINDOW_SERVICE)来获取WindowManager

使用WindowManager可以在其他应用最上层,甚至手机桌面最上层显示窗口。

调用的是WindowManager继承自基类的addView方法和removeView方法来显示和隐藏窗口。具体见后面的实例。

另:API 17推出了Presentation,它将自动获取displayContext和WindowManager,可以方便地在另一个display上显示窗口。

WindowManager实现悬浮窗需要声明权限

  首先在manifest中添加如下权限:

<!-- 显示顶层浮窗 --><uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

  注意:在MIUI上需要在设置中打开本应用的”显示悬浮窗”开关,并且重启应用,否则悬浮窗只能显示在本应用界面内,不能显示在手机桌面上。

服务获取和基本参数设置

[java] view plain copy print?在CODE上查看代码片派生到我的代码片
// 获取应用的Context
 mContext = context.getApplicationContext();
 // 获取WindowManager
 mWindowManager = (WindowManager) mContext
     .getSystemService(Context.WINDOW_SERVICE);
参数设置:
 final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
 // 类型
 params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
 // WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
 // 设置flag
 int flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
 // | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 // 如果设置了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,弹出的View收不到Back键的事件
 params.flags = flags;
 // 不设置这个弹出框的透明遮罩显示为黑色
 params.format = PixelFormat.TRANSLUCENT;
 // FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口
 // 设置 FLAG_NOT_FOCUSABLE 悬浮窗口较小时,后面的应用图标由不可长按变为可长按
 // 不设置这个flag的话,home页的划屏会有问题
 params.width = LayoutParams.MATCH_PARENT;
 params.height = LayoutParams.MATCH_PARENT;
 params.gravity = Gravity.CENTER; 

点击和按键事件

  除了View中的各个控件的点击事件之外,弹窗View的消失控制需要一些处理。

  点击弹窗外部可隐藏弹窗的效果,首先,悬浮窗是全屏的,只不过最外层的是透明或者半透明的:

具体实现

[java] view plain copy print?在CODE上查看代码片派生到我的代码片
package com.robert.floatingwindow;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.WindowManager.LayoutParams;
import android.widget.Button;
/**
* 弹窗辅助类
*
* @ClassName WindowUtils
*
*
*/
public class WindowUtils {
  private static final String LOG_TAG = "WindowUtils";
  private static View mView = null;
  private static WindowManager mWindowManager = null;
  private static Context mContext = null;
  public static Boolean isShown = false;
  /**
   * 显示弹出框
   *
   * @param context
   * @param view
   */
  public static void showPopupWindow(final Context context) {
    if (isShown) {
      LogUtil.i(LOG_TAG, "return cause already shown");
      return;
    }
    isShown = true;
    LogUtil.i(LOG_TAG, "showPopupWindow");
    // 获取应用的Context
    mContext = context.getApplicationContext();
    // 获取WindowManager
    mWindowManager = (WindowManager) mContext
        .getSystemService(Context.WINDOW_SERVICE);
    mView = setUpView(context);
    final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
    // 类型
    params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
    // WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
    // 设置flag
    int flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
    // | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
    // 如果设置了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,弹出的View收不到Back键的事件
    params.flags = flags;
    // 不设置这个弹出框的透明遮罩显示为黑色
    params.format = PixelFormat.TRANSLUCENT;
    // FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口
    // 设置 FLAG_NOT_FOCUSABLE 悬浮窗口较小时,后面的应用图标由不可长按变为可长按
    // 不设置这个flag的话,home页的划屏会有问题
    params.width = LayoutParams.MATCH_PARENT;
    params.height = LayoutParams.MATCH_PARENT;
    params.gravity = Gravity.CENTER;
    mWindowManager.addView(mView, params);
    LogUtil.i(LOG_TAG, "add view");
  }
  /**
   * 隐藏弹出框
   */
  public static void hidePopupWindow() {
    LogUtil.i(LOG_TAG, "hide " + isShown + ", " + mView);
    if (isShown && null != mView) {
      LogUtil.i(LOG_TAG, "hidePopupWindow");
      mWindowManager.removeView(mView);
      isShown = false;
    }
  }
  private static View setUpView(final Context context) {
    LogUtil.i(LOG_TAG, "setUp view");
    View view = LayoutInflater.from(context).inflate(R.layout.popupwindow,
        null);
    Button positiveBtn = (Button) view.findViewById(R.id.positiveBtn);
    positiveBtn.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        LogUtil.i(LOG_TAG, "ok on click");
        // 打开安装包
        // 隐藏弹窗
        WindowUtils.hidePopupWindow();
      }
    });
    Button negativeBtn = (Button) view.findViewById(R.id.negativeBtn);
    negativeBtn.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        LogUtil.i(LOG_TAG, "cancel on click");
        WindowUtils.hidePopupWindow();
      }
    });
    // 点击窗口外部区域可消除
    // 这点的实现主要将悬浮窗设置为全屏大小,外层有个透明背景,中间一部分视为内容区域
    // 所以点击内容区域外部视为点击悬浮窗外部
    final View popupWindowView = view.findViewById(R.id.popup_window);// 非透明的内容区域
    view.setOnTouchListener(new OnTouchListener() {
      @Override
      public boolean onTouch(View v, MotionEvent event) {
        LogUtil.i(LOG_TAG, "onTouch");
        int x = (int) event.getX();
        int y = (int) event.getY();
        Rect rect = new Rect();
        popupWindowView.getGlobalVisibleRect(rect);
        if (!rect.contains(x, y)) {
          WindowUtils.hidePopupWindow();
        }
        LogUtil.i(LOG_TAG, "onTouch : " + x + ", " + y + ", rect: "
            + rect);
        return false;
      }
    });
    // 点击back键可消除
    view.setOnKeyListener(new OnKeyListener() {
      @Override
      public boolean onKey(View v, int keyCode, KeyEvent event) {
        switch (keyCode) {
        case KeyEvent.KEYCODE_BACK:
          WindowUtils.hidePopupWindow();
          return true;
        default:
          return false;
        }
      }
    });
    return view;
  }
} 

总结

以上就是本文的全部内容,本文以实例形式较为详细的分析了Android悬浮窗口的原理与具体实现技巧,具有一定参考借鉴价值,希望给大家在开发Android应用中有所帮助。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索android
, 全局activity
, 悬浮activity
全局悬浮窗
android 悬浮activity、activity透明悬浮窗口、悬浮activity、安卓开发悬浮activity、activity 悬浮按钮,以便于您获取更多的相关知识。

时间: 2024-05-04 11:08:51

不依赖于Activity的Android全局悬浮窗的实现_Android的相关文章

不依赖于Activity的Android全局悬浮窗的实现

前言 当我们在手机上使用360安全卫士时,手机屏幕上时刻都会出现一个小浮动窗口,点击该浮动窗口可跳转到安全卫士的操作界面,而且该浮动窗口不受其他activity的覆盖影响仍然可见(多米音乐也有相关的和主界面交互的悬浮小窗口).那么这种不受Activity界面影响的悬浮窗口是怎么实现的呢? Android悬浮窗实现 实现基础 Android悬浮窗实现使用WindowManager WindowManager介绍 通过Context.getSystemService(Context.WINDOW_S

Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果

首先是一个小的悬浮窗显示的是当前使用了百分之多少的内存,点击一下小悬浮窗,就会弹出一个大的悬浮窗,可以一键加速.好,我们现在就来模拟实现一下类似的效果. 先谈一下基本的实现原理,这种桌面悬浮窗的效果很类似与Widget,但是它比Widget要灵活的多.主要是通过WindowManager这个类来实现的,调用这个类的addView方法用于添加一个悬浮窗,updateViewLayout方法用于更新悬浮窗的参数,removeView用于移除悬浮窗.其中悬浮窗的参数有必要详细说明一下. WindowM

详解Android全局异常的捕获处理_Android

在Android开发中在所难免的会出现程序crash,俗称崩溃.用户的随意性访问出现测试时未知的Bug导致我们的程序crash,此时我们是无法直接获取的错误log的,也就无法修复Bug.这就会极大的影响用户体验,此时我们需要注册一个功能来捕获全局的异常信息,当程序出现crash信息,我们把错误log记录下来,上传到服务器,以便于我们能及时修复bug.实现这个功能我们需要依赖于UncaughtExceptionHandler这个类,UncaughtExceptionHandler是一个接口,在Th

Android手机悬浮窗口小案例_Android

本文实例为大家分享了Android九宫格图片展示的具体代码,供大家参考,具体内容如下 –主页面--– //布局中就一个Button public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);

android-求助:Android ScrollView中生成windowManager桌面悬浮窗问题

问题描述 求助:Android ScrollView中生成windowManager桌面悬浮窗问题 我想在scrollView中做一个可以拖动的悬浮窗,但是拖动的时候 悬浮窗没动,ScrollView上线滑动了,请求解决办法 解决方案 Android桌面悬浮窗 解决方案二: 给窗口设置触摸监听,然后触摸的时候,让ScrollView不要拦截事件,交由窗体处理,代码如下 lv.setOnTouchListener(new View.OnTouchListener() { @Override pub

在当前Activity之上创建悬浮view之WindowManager悬浮窗效果

最近有学生做毕业设计,想使用悬浮窗这种效果,其实很简单,我们可以通过系统服务WindowManager来实现此功能,本章我们来试验一下在当前Activity之上创建一个悬浮的view. 第一步:认识WindowManager 这个接口用于与 window manager (窗口管理器, 应用框架层) 进行交互. 通过getSystemService(Context.WINDOW_SERVICE)可以获取到WM的实例. 继承关系 public interface WindowManager imp

android悬浮窗-android写了一个悬浮窗,但是输入法显示不出来了,希望能得到朋友们的帮助,谢谢了。

问题描述 android写了一个悬浮窗,但是输入法显示不出来了,希望能得到朋友们的帮助,谢谢了. 用android编写了悬浮窗,项目是用Unity3d做的,项目中的输入法软键盘无法显示了,能接收到按键,但是软键盘看不到. windowParams的参数如下,主要的问题在flags windowParams.type = LayoutParams.TYPE_PHONE; windowParams.format = PixelFormat.RGBA_8888; windowParams.flags

Android学习教程之悬浮窗菜单制作(9)_Android

本文实例为大家分享了Android悬浮窗菜单的具体代码,供大家参考,具体内容如下 MainActivity.java代码: package siso.multilistview; import android.os.Build; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; public class MainActivity extends

Android实现桌面悬浮窗、蒙板效果实例代码

现在很多安全类的软件,比如360手机助手,百度手机助手等等,都有一个悬浮窗,可以飘浮在桌面上,方便用户使用一些常用的操作. 今天这篇文章,就是介绍如何实现桌面悬浮窗效果的. 首先,看一下效果图. 悬浮窗一共分为两个部分,一个是平常显示的小窗口,另外一个是点击小窗口显示出来的二级悬浮窗口. 首先,先看一下这个项目的目录结构. 最关键的就是红框内的四个类. 首先,FloatWindowService是一个后台的服务类,主要负责在后台不断的刷新桌面上的小悬浮窗口,否则会导致更换界面之后,悬浮窗口也会随