序言

Android悬浮窗的实现,主要有四个步骤: 1. 声明及申请权限 2. 构建悬浮窗需要的控件 3. 将控件添加到WindowManager 4. 必要时更新WindowManager的布局

一、权限申请

需要在 AndroidMainfest.xml 中声明权限

在6.0以上的时候(现在基本都是6.0以上的了),还需要用户手动打开悬浮窗权限。

int REQUEST_CODE = 520 ;

Intent intent= new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));

startActivityForResult(intent, REQUEST_CODE);

因为会跳转到设置界面,所以最好先弹出提示框,待用户点击确定后再进行跳转。

具体代码,可以参考一下:

private static final int RESULT_CODE_BOX = 10023;

@TargetApi(Build.VERSION_CODES.M)

private void checkBoxPower() {

if (!Settings.canDrawOverlays(mContext)) {

Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + mContext.getPackageName()));//权限申请页面

mActivity.startActivityForResult(intent, RESULT_CODE_BOX);

}

}

@TargetApi(Build.VERSION_CODES.M)

public void onActivityResult(int requestCode, int resultCode, Intent data){

if(requestCode == RESULT_CODE_BOX){

if (!Settings.canDrawOverlays(mContext)) {

Log.e(TAG,"授权失败");

} else {

Log.e(TAG,"授权成功");

//启动悬浮窗的Service

Intent intent = new Intent(mActivity, FloatingService.class);

mActivity.startService(intent);

}

}

}

Settings.canDrawOverlays 为检查是否有悬浮窗权限的方法,如果已经有权限的时候返回true。

二、悬浮窗初始化

具体代码,可以参考一下:

private WindowManager windowManager;

private WindowManager.LayoutParams layoutParams;

//悬浮窗的初始位置

private static int FloatingInitialPosition_x = 50;

private static int FloatingInitialPosition_y = 50;

//初始化悬浮窗

private void initFrame(){

windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

layoutParams = new WindowManager.LayoutParams();//windowManager的布局

if (Build.VERSION.SDK_INT >= 26) { //8.0以上只能使用 TYPE_APPLICATION_OVERLAY窗口类型来创建悬浮窗

layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;

} else {

layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;

}

layoutParams.format = PixelFormat.RGBA_8888;//设置图片格式

layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;

layoutParams.gravity = Gravity.LEFT | Gravity.TOP;//悬浮框在布局的位置

layoutParams.x = FloatingInitialPosition_x; //初始位置的x坐标,相对于gravity

layoutParams.y = FloatingInitialPosition_y;

layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;//指定长宽

layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;

floatView = View.inflate(getApplicationContext(), R.layout.float_box_view, null);

}

//展示悬浮窗

private View floatView;

private void showFloatingWindow() {

windowManager.addView(floatView, layoutParams);

}

悬浮窗需要在别的程序之上显示,就需要通过WindowManager获取WINDOW_SERVICE系统服务,然后通过windowManager.addView把相应的view添加进去。 8.0以上版本时,窗口类型修改为了WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 一个最简单的悬浮窗到此就结束了。

三、拖动功能

这个功能是悬浮窗中很常见的功能,要实现这个功能就需要用到触摸事件的处理View.OnTouchListener。 具体代码,可以参考一下:

floatView.setOnTouchListener(new FloatingOnTouchListener()); //悬浮窗的滑动监听

//滑动监听

private class FloatingOnTouchListener implements View.OnTouchListener {

private int x;

private int y;

@Override

public boolean onTouch(View view, MotionEvent event) {

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

x = (int) event.getRawX();

y = (int) event.getRawY();

break;

case MotionEvent.ACTION_MOVE:

int nowX = (int) event.getRawX();

int nowY = (int) event.getRawY();

int movedX = nowX - x;

int movedY = nowY - y;

x = nowX;

y = nowY;

layoutParams.x = layoutParams.x + movedX;

layoutParams.y = layoutParams.y + movedY;

windowManager.updateViewLayout(floatView, layoutParams);

break;

default:

break;

}

return false;

}

}

监听滑动做成xy的变化,并刷新windowManager就可以了。 这里有一点要注意的是,如果同时使用OnTouchListener和setOnClickListener,那每次移动都会同时触发点击事件,所以这里需要做一个判断。

三、只在应用内显示

悬浮窗不需要在别的程序上显示,也不需要在桌面上显示,只需要它在本APP内显示就可以了。 其中的一种方法就是监听App是否在前台,如果在,则显示。如果不在则隐藏。 App不在前台了,可能有三种情况:1、正常退出。2、home键回到主界面了。3、点击任务键切换到别的程序。 正常退出的情况,只要我们也正常销毁悬浮窗就好。 home键和多任务键的情况,需要对按键进行监听。然后判断当前App是否在前台,如果不是,则是隐藏/销毁悬浮窗。 判断当前App是否在前台的代码可以参考:

public static boolean isAppOnForeground(Context context) {

ActivityManager activityManager = (ActivityManager) context.getApplicationContext()

.getSystemService(Context.ACTIVITY_SERVICE);

String packageName = context.getApplicationContext().getPackageName();

//获取Android设备中所有正在运行的App

List appProcesses = activityManager.getRunningAppProcesses();

if (appProcesses == null)

return false;

for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {

if (appProcess.processName.equals(packageName)

&& appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {

return true;

}

}

return false;

}

home键和多任务键的监听代码,可以参考:

InnerRecevier innerReceiver = new InnerRecevier();

IntentFilter intentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);

registerReceiver(innerReceiver, intentFilter);

class InnerRecevier extends BroadcastReceiver {

final String SYSTEM_DIALOG_REASON_KEY = "reason";

final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";

final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";

@Override

public void onReceive(Context context, Intent intent) {

String action = intent.getAction();

if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {

String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);

if (reason != null) {

if (reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) {

Toast.makeText(MainActivity.this, "Home键被监听", Toast.LENGTH_SHORT).show();

} else if (reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {

Toast.makeText(MainActivity.this, "多任务键被监听", Toast.LENGTH_SHORT).show();

}

}

}

}

}

另一种方法是使用ViewGroup。 ViewGroup是不需要权限申请的,直接显示。( ViewGroup方法 和上面的代码是没有关联的) 如果是为unity游戏做的Android SDK,可以直接获取最顶层的view,然后把悬浮窗的view加载进来。因为unity游戏大多只有一个Activity。 具体代码,可以参考一下:(这个也可以作为广告的容器来填充广告,这段示例代码当时就是用来填充广告的)

ViewGroup view = (ViewGroup )AppActivity.getWindow().getDecorView();//获取最顶层的view

ViewGroup bannerContainer=(ViewGroup) View.inflate(AppActivity, R.layout.activity_banner_bottom, view).findViewById(R.id.bannerContainer);//为其添加一个布局

bannerContainer.addView(adVeiw);//把悬浮窗的view加进来

如果是普通的APP,并不只有一个Activity。所以需要使用到Application.ActivityLifecycleCallbacks方法。 ActivityLifecycleCallbacks为Activity生命周期监控接口的方法,它包含了一整套Activity的生命周期回调方法,只要有一个Activity触发了声明周期,这个接口的回调就会触发,并且传回触发生命周期方法的Activity对象。 在拿到当前显示的Activity之后,通过activity.getWindow().getDecorView() 来获取Activity的视图组。然后把悬浮窗的view加进去。切换Activity时,把悬浮窗的view销毁,在新显示的Activity同样把悬浮窗的view加进去。

示例源码

Android展开悬浮窗功能,Android 悬浮窗 (附圆形菜单悬浮窗)相关推荐

  1. Android-悬浮窗功能的实现(附Java、KT实现源码,自学Android

    跳转到开启悬浮窗权限页面.如果悬浮窗权限已开启,直接将当前任务栈置于后台,开启服务即可. 其实回调方法,并没有直接告诉我们是否授权成功,所以我们需要在回调中再次判断 override fun onAc ...

  2. android动态view展开和收起功能,Android实现长图展开与收起效果

    前言: 在app的文章中,经常会夹杂着一些特别长的长图.在阅读的时候需要滑动很久才能看图片下方的文字,因此对于长图只展示图片上面一部分,并且可以展开这个功能是很重要的. 效果: 基本思路: 利用sca ...

  3. Android实现支付宝AR功能,Android接入支付宝实现支付功能实例

    我本来是想直接讲Android支付这一块的,包括支付宝,微信,其他第三方整合支付等,但是微信开放平台他对我的账号做了限制,所有我今天就先把重心放在支付宝的支付上,也算是写得尽可能详细些吧,毕竟是第三方 ...

  4. android 实现屏幕录制功能,Android实现屏幕录制功能

    本文实例为大家分享了Android实现屏幕录制功能的具体代码,供大家参考,具体内容如下 1.效果图: 2.添加依赖 dependencies { implementation fileTree(dir ...

  5. android的手势解锁功能,Android应用开发之Android 5秒学会使用手势解锁功能

    本文将带你了解Android应用开发Android 5秒学会使用手势解锁功能,希望本文对大家学Android有所帮助. Android手势解锁 本文讲述的是一个手势解锁的库,可以定制显示隐藏宫格点.路 ...

  6. android如何实现打分功能,Android App中使用RatingBar实现星级打分功能的教程

    RatingBar简单介绍RatingBar是基于SeekBar(拖动条)和ProgressBar(状态条)的扩展,用星形来显示等级评定,在使用默认RatingBar时,用户可以通过触摸/拖动/按键( ...

  7. android 手机录屏功能,Android录屏功能的实现

    最近做一个Android开发的项目用到了录屏的功能,开始查阅了一些资料和博客,基本上都是在讨论ROOT的.直到后来在github上看到一个比较新的代码,才恍然发现,Android 5.0时候开放了一个 ...

  8. android studio发邮件功能,Android发送邮件的方法实例详解

    本文实例讲述了Android发送邮件的方法.分享给大家供大家参考,具体如下: 在android手机中实现发送邮件的功能也是不可缺少的.如何实现它呢?下面以简单的例子进行说明. 程序如下: import ...

  9. android实现qq登录功能,Android 实现QQ第三方登录

    陆续整理一下 QQ.新浪,以及微信 登录和分享功能. 步骤: 1 下载官方sdk 2. 根据官网文档及Demo测试. 3.集成到自己应用上. 首先下载下来,导入到我们的开发工具中,看下具体工程. 所谓 ...

最新文章

  1. 记一次suse linux崩溃
  2. SpringBoot简单使用
  3. 矢量合成和分解的法则_高考复习整理力的合成和分解
  4. 【栈】【232. 用栈实现队列】【简单】
  5. windows系统如何查看端口被占用、杀进程
  6. ABAP Netweaver Authorization trace tool
  7. squirrel-foundation-demo
  8. DataList的使用,Repeater
  9. maven更新总结与tomcat发布方法总结
  10. LINQ系列:Linq to Object集合操作符
  11. [Linux]Linux man命令的使用方法
  12. Java中System.getProperty()的作用及使用
  13. stm32f4 dma da正弦波发生器 keil5 hal库 CubeMX
  14. 南昌大学大一C语言程序试卷,南昌大学C语言题库
  15. php快递按选择次数排序,php快递接口查询api 不限制次数
  16. 微信扫二维码下载apk跳转浏览器打开的方式(及微信屏蔽下载解决方案)
  17. CST学习:圆形贴片天线四元阵设计(一)阵元设计
  18. 整理 Go 语言中 20 个占位符!
  19. 【资讯】FL6410改名OK6410-B,硬件接口丰富,挑战mini6410送19张ARM光盘
  20. 手机投屏到电脑 -- 小黑超细日常教程

热门文章

  1. 我用Python分析5W+视频数据,看看谁才是最咕UP主
  2. getchar ,putchar,gets,puts的辨析
  3. USB Mass Storage 6.7 The Thirteen Cases章节的理解
  4. 关于AP, MAP的一些理解
  5. 索尼Xperia XZ1 Compact刷机后的问题,电量一直锁定20%,手机卡无信号无服务,相机拍照成纯绿色图片
  6. PostgresConf.CNPGConf.Asia 2020五洲相会
  7. 万众瞩目!ICF5国产开源飞控推出,为国内无人系统发力
  8. python cv2什么意思_这次一定要记住opencv和cv2是什么及其基础用法
  9. 一张图看明白电信云解决方案架构
  10. c语言程序如下,某C语言程序如下: #include stdio.h void main() { floa.._简答题试题答案...