1、需求

首先说一下需求吧,看看是不是你们想要的:
在IM音视频聊天页面,点击页面上的最小化按钮,将Activity最小化并开启一个悬浮窗,悬浮窗可拖动可点击,点击进入当前通话页面。

2、思路

1、听到开启悬浮窗,第一时间就想到了要开启一个Service,在Service中进行布局的设置及拖动、点击逻辑的设定。
2、通话界面点击最小化按钮,将Activity最小化并保持后台运行,同时开启Service展示悬浮窗

3、实现

1、创建FloatVideoWindowService继承Service类
2、实现父类抽象方法
3、在onCreate()中进行布局设置,并获得WindowManager对象。
4、在onStartCommand()方法中将布局、参数添加到WindowManager中
5、增加全局变量boolean isStarted记录悬浮窗是否已打开。
6、在onDestroy()中将布局从WindowManager中移除
7、在onStartCommand()中进行控件的点击、拖动监听
8、点击最小化按钮执行moveTaskToBack(true),并启动Service,isStarted = true;
9、onRestart()中关闭Service;

以下是代码

Service.class

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.SystemClock;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;public class FloatVideoWindowService extends Service {private WindowManager mWindowManager;private WindowManager.LayoutParams wmParams;private LayoutInflater inflater;public static boolean isStarted = false;//viewprivate View mFloatingLayout;    //布局View@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();isStarted = true;initWindow();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {showFloatingWindow();return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {super.onDestroy();if (mWindowManager != null) {mWindowManager.removeView(mFloatingLayout);isStarted = false;}}/*** 设置悬浮框基本参数(位置、宽高等)*/private void initWindow() {mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);wmParams = getParams();inflater = LayoutInflater.from(getApplicationContext());mFloatingLayout = inflater.inflate(R.layout.layout_window, null);}private WindowManager.LayoutParams getParams() {wmParams = new WindowManager.LayoutParams();if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;} else {wmParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;}wmParams.format = PixelFormat.RGBA_8888;//设置可以显示在状态栏上wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;//这是悬浮窗居中位置wmParams.gravity = Gravity.LEFT | Gravity.TOP;//70、210是我项目中的位置哦wmParams.x = 70;wmParams.y = 210;return wmParams;}private void showFloatingWindow() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//判断系统版本if (Settings.canDrawOverlays(this)) {mFloatingLayout.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(getApplicationContext(), VoiceCallActivity.class);startActivity(intent);}});mFloatingLayout.setOnTouchListener(new FloatingListener());mWindowManager.addView(mFloatingLayout, wmParams);}} else {mFloatingLayout.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(getApplicationContext(), VoiceCallActivity.class);startActivity(intent);}});mFloatingLayout.setOnTouchListener(new FloatingListener());mWindowManager.addView(mFloatingLayout, wmParams);}}private int mTouchStartX, mTouchStartY, mTouchCurrentX, mTouchCurrentY;private int mStartX, mStartY, mStopX, mStopY;private boolean isMove;private class FloatingListener implements View.OnTouchListener {@Overridepublic boolean onTouch(View v, MotionEvent event) {int action = event.getAction();switch (action) {case MotionEvent.ACTION_DOWN:isMove = false;mTouchStartX = (int) event.getRawX();mTouchStartY = (int) event.getRawY();mStartX = (int) event.getX();mStartY = (int) event.getY();break;case MotionEvent.ACTION_MOVE:mTouchCurrentX = (int) event.getRawX();mTouchCurrentY = (int) event.getRawY();wmParams.x += mTouchCurrentX - mTouchStartX;wmParams.y += mTouchCurrentY - mTouchStartY;mWindowManager.updateViewLayout(mFloatingLayout, wmParams);mTouchStartX = mTouchCurrentX;mTouchStartY = mTouchCurrentY;break;case MotionEvent.ACTION_UP:mStopX = (int) event.getX();mStopY = (int) event.getY();if (Math.abs(mStartX - mStopX) >= 1 || Math.abs(mStartY - mStopY) >= 1) {isMove = true;}break;}return isMove;}}
}
Activity.class
private Intent serviceIntent;private static HomeWatcherReceiver mHomeKeyReceiver = null;public void openMinWindow() {if (!FloatVideoWindowService.isStarted) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//判断系统版本if (!Settings.canDrawOverlays(this)) {Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT);startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 0);} else {serviceIntent = new Intent(VoiceCallActivity.this, FloatVideoWindowService.class);startService(serviceIntent);moveTaskToBack(true);}} else {serviceIntent = new Intent(VoiceCallActivity.this, FloatVideoWindowService.class);startService(serviceIntent);moveTaskToBack(true);}}}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if (requestCode == 0) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if (!Settings.canDrawOverlays(this)) {Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();} else {Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();serviceIntent = new Intent(VoiceCallActivity.this, FloatVideoWindowService.class);startService(serviceIntent);moveTaskToBack(true);}}}}@Overrideprotected void onRestart() {super.onRestart();if (serviceIntent != null) {stopService(serviceIntent);}}//以下为Home键监听,最小化到桌面时也让悬浮窗启动@Subscribepublic void onEvent(String event) {if (event.equals("startService")) {openMinWindow();}}@Overrideprotected void onResume() {super.onResume();registerHomeKeyReceiver(this);}@Overrideprotected void onPause() {super.onPause();unregisterHomeKeyReceiver(this);}private static void registerHomeKeyReceiver(Context context) {mHomeKeyReceiver = new HomeWatcherReceiver();final IntentFilter homeFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);context.registerReceiver(mHomeKeyReceiver, homeFilter);}private static void unregisterHomeKeyReceiver(Context context) {if (null != mHomeKeyReceiver) {context.unregisterReceiver(mHomeKeyReceiver);}}
HomeWatcherReceiver.class (手机底部按键监听)
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import de.greenrobot.event.EventBus;/*** PROJECT_NAME:meteor_dog_android* Created by ENZO on 2018/10/19,16:18* Description: Home键监听*/public class HomeWatcherReceiver extends BroadcastReceiver {private static final String LOG_TAG = "HomeReceiver";private static final String SYSTEM_DIALOG_REASON_KEY = "reason";private static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";private static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";private static final String SYSTEM_DIALOG_REASON_LOCK = "lock";private static final String SYSTEM_DIALOG_REASON_ASSIST = "assist";@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();Log.i(LOG_TAG, "onReceive: action: " + action);if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);Log.i(LOG_TAG, "reason: " + reason);if (SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason)) {//发送通知,启动ServiceEventBus.getDefault().post("startService");}else if (SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) {// 长按Home键 或者 activity切换键}else if (SYSTEM_DIALOG_REASON_LOCK.equals(reason)) {// 锁屏}else if (SYSTEM_DIALOG_REASON_ASSIST.equals(reason)) {// samsung 长按Home键}}}}

4、注意

4.1: Service记得在AndroidManifest.xml中注册哦
4.2: 6.0以上(23)判断是否有悬浮窗权限请用Settings.canDrawOverlays(this)方法
4.3: 需要添加权限 android.permission.SYSTEM_ALERT_WINDOW
4.4: Eventbus记得解除注册啊!!我深有体会[尴尬]

android悬浮窗(支持退回桌面后显示)相关推荐

  1. android显示二维毫秒,Android 悬浮窗显示毫秒级时间

    Android 悬浮窗显示毫秒级时间Android 悬浮窗显示毫秒级时间. 运行效果如下: 1.新建工程"FloatWindowDemo2", 工程如下: 2. "Mai ...

  2. android显示二维毫秒,Android应用开发Android 悬浮窗显示毫秒级时间

    本文将带你了解Android应用开发Android 悬浮窗显示毫秒级时间,希望本文对大家学Android有所帮助. Android   悬浮窗显示毫秒级时间Android 悬浮窗显示毫秒级时间. 运行 ...

  3. android悬浮窗语音识别demo

    带有android悬浮窗的语音识别语义理解demo 如发现代码排版问题,请访问CSDN博客 Android桌面悬浮窗实现比较简单,本篇以一个语音识别,语义理解的demo来演示如何实现android悬浮 ...

  4. Android悬浮窗原理解析(Window)[源码]

    悬浮窗,在大多数应用中还是很少见的,目前我们接触到的悬浮窗,差不多都是一些系统级的应用软件,例如:360安全卫士,腾讯手机管家等:在某些服务行业如金融,餐饮等,也会在应用中添加悬浮窗,例如:美团的偷红 ...

  5. 安卓java浮层不响应点击事件,Android悬浮窗屏蔽悬浮窗外部所有的点击事件的实例代码...

    Android可以在所有应用上方添加View,就是给WindowManager添加一个View,在创建的View的时候可以给这个View设置LayoutParams(android.view.Wind ...

  6. Android 悬浮窗语音识别功能开发详解

    笔者是一个普通不能再普通的程序员,本着出处兴趣,花时间研究了一下,想实现手机的悬浮窗语音识别功能,这样不影响自己其它操作的,语音识别技术是用百度云语音sdk,应该不难实现,很难实现就是核心语音识别技术 ...

  7. Android 悬浮窗功能的实现

    前言 我们大多数在两种情况下可以看到悬浮窗,一个是视频通话时的悬浮窗,另一个是360卫士的悬浮球,实现此功能的方式比较多,这里以视频通话悬浮窗中的需求为例.编码实现使用Kotlin.Java版本留言邮 ...

  8. Android悬浮窗的简单实现

    1. 前言 现在很多应用都有小悬浮窗的功能,比如看直播的时候,通过Home键返回桌面,直播的小窗口仍可以在屏幕上显示.下面将介绍下悬浮窗的的一种简单实现方式. 2.原理 Window我们应该很熟悉,它 ...

  9. Android展开悬浮窗功能,Android 悬浮窗 (附圆形菜单悬浮窗)

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

最新文章

  1. c#如何通过ftp上传文件_定时上传文件到ftp,2步完成Windows系统定时上传文件到ftp...
  2. 阿里全资收购一家核心技术公司,中科院大牛带队加盟
  3. Go(GoLang)解决 cannot find package/golang.org/问题 Grpc+ProtoBuf所需的一些资源
  4. Crossing River(信息学奥赛一本通-T1232)
  5. 今天你写控件了吗?----ASP.net控件开发系列(八)
  6. 6. 吴恩达机器学习课程-作业6-SVM
  7. 【Java 常用类】java.util包(5)Date类的常用方法
  8. Android机顶盒网络地址端口连通性测试
  9. Word参考文献交叉引用——连续多项引用
  10. 环境安装(二):windows10下安装caffe框架(cuda10.0、cudnn7.6.4)
  11. 软件测试缺陷报告的5c标准
  12. 全基因组测序数据分析---WGS主流程
  13. Android—调用高德地图显示定位蓝点
  14. macOS开发中用TagLib获取、修改音频文件信息
  15. Android 系统剪贴板的使用 - 复制、获取和清空
  16. python 桑基图_流量结构分布图——桑基图(Sankey)
  17. Redis看这一篇就够了
  18. Cisco ❀ 数据封装
  19. r5处理器_R5-4600H和i5-10400差距多大?
  20. linux操作系统应用技术 周志敏,Linux操作系统应用技术

热门文章

  1. Apple Sign in with Apple(苹果授权登录PHP)
  2. matlab 自激振荡,自激振荡系统matlab仿真课程设计
  3. 架构师之路(七)之五视图方法论
  4. 【C语言】求最小公倍数三种方法
  5. 洛谷 P3975 [TJOI2015]弦论 解题报告
  6. Xcode 禁用indexing
  7. Kaggle项目之Mobile App Store
  8. electron打包时报错could not find: “C:\Users\xxxx\AppData\Local\Temp\t-OLh5E0\0-messages.nsh“
  9. 中科大计算机考研录取分数线_2017计算机专业学校考研难度排行榜,计算机考研难度排名...
  10. android 系统隐藏和显示虚拟按键的几种方法