Android悬浮窗
今天给大家写一个这个Android悬浮窗的功能,这个功能一般在360,酷狗(桌面歌词),网易云音乐(桌面歌词)上面用到,一般开发是很少碰到这个功能的,但是这个悬浮窗功能可以帮助理解Android的绘制机制。
这个功能大概是这样的,我们进一个Activity,在onCreate里面开启一个Service,在服务器里添加一个悬浮窗,然后退出Activity.
Activity:
package com.example.library;import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.widget.Toast;
import com.example.library.service.MainService;public class SecondActivity extends BaseActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//不需要setContentViewif (Build.VERSION.SDK_INT >= 23) {if (Settings.canDrawOverlays(SecondActivity.this)) {Intent intent = new Intent(SecondActivity.this, MainService.class);Toast.makeText(SecondActivity.this,"已开启Toucher",Toast.LENGTH_SHORT).show();startService(intent);finish();} else {//若没有权限,提示获取.Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);Toast.makeText(SecondActivity.this,"需要取得权限以使用悬浮窗",Toast.LENGTH_SHORT).show();startActivity(intent);}} else {//SDK在23以下,不用管.Intent intent = new Intent(SecondActivity.this, MainService.class);startService(intent);finish();}}}
然后再是Service:
package com.example.library.service;import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.os.SystemClock;
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.ImageButton;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.example.library.R;public class MainService extends Service {//Log用的TAGprivate static final String TAG = "MainService";//布局参数.WindowManager.LayoutParams params;//实例化的WindowManager.WindowManager windowManager;RelativeLayout toucherLayout;ImageButton imageButton1;//状态栏高度.(接下来会用到)int statusBarHeight = -1;@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();Log.i("MainService" , "onCreate==onCreate");//OnCreate中来生成悬浮窗.createToucher();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i("MainService" , "onCreate==onStartCommand");return super.onStartCommand(intent, flags, startId);}private void createToucher(){//赋值WindowManager&LayoutParam.params = new WindowManager.LayoutParams();windowManager = (WindowManager)getBaseContext(). getSystemService(Context.WINDOW_SERVICE);//设置type.系统提示型窗口,一般都在应用程序窗口之上.//这个是8.0系统以下的
// params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;//这个是8.0系统以上params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;//设置效果为背景透明.params.format = PixelFormat.RGBA_8888;//设置flags.不可聚焦及不可使用按钮对悬浮窗进行操控.params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;//设置窗口初始停靠位置.params.gravity = Gravity.LEFT | Gravity.TOP;params.x = 0;params.y = 0;//设置悬浮窗口长宽数据.//注意,这里的width和height均使用px而非dp.这里我偷了个懒//如果你想完全对应布局设置,需要先获取到机器的dpi//px与dp的换算为px = dp * (dpi / 160).params.width = WindowManager.LayoutParams.MATCH_PARENT;params.height = 300;LayoutInflater inflater = LayoutInflater.from(getApplication());toucherLayout = (RelativeLayout) inflater.inflate(R.layout.layout_main , null);imageButton1 = toucherLayout.findViewById(R.id.imageView);//主动计算出当前View的宽高信息.
// toucherLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);//用于检测状态栏高度.int resourceId = getResources().getIdentifier("status_bar_height","dimen","android");if (resourceId > 0){statusBarHeight = getResources().getDimensionPixelSize(resourceId);}Log.i(TAG,"状态栏高度为:" + statusBarHeight);//其他代码...imageButton1.setOnClickListener(new View.OnClickListener() {long[] hints = new long[2];@Overridepublic void onClick(View v) {Log.i(TAG,"点击了");System.arraycopy(hints,1,hints,0,hints.length -1);hints[hints.length -1] = SystemClock.uptimeMillis();if (SystemClock.uptimeMillis() - hints[0] >= 700){Log.i(TAG,"要执行");Toast.makeText(MainService.this,"连续点击两次以退出", Toast.LENGTH_SHORT).show();}else{Log.i(TAG,"即将关闭");stopSelf();}}});imageButton1.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {//ImageButton我放在了布局中心,布局一共300dpparams.x = (int) event.getRawX() - 150;//这就是状态栏偏移量用的地方params.y = (int) event.getRawY() - 150 - statusBarHeight;windowManager.updateViewLayout(toucherLayout,params);return false;}});windowManager.addView(toucherLayout , params);}@Overridepublic void onDestroy(){if (windowManager != null){windowManager.removeView(toucherLayout);}super.onDestroy();}
}
然后配置Service
然后就是权限配置
然后就是去手机系统设置打开:在其他应用上层显示
然后效果出来啦
以上就是一个简单的悬浮窗口功能 说到这里就不难明白,Activity并不是我们唯一显示布局的组件,这个是为什么,原来我们的Activity只是一个用来承载我们布局的中间件,它本身不负责绘制,我们写的xml文件是在Window对象里面执行的,Window的实现类是PhoneWindow,PhoneWindow里面有一个WindowManager,然后把我们的View传给WinowManagerImpl,再传给WindowManagerGlobal,再传给ViewRootImpl,ViewRootImpl里面负责事件处理跟图像绘制,所以Activity其实也是把view给WindowManager处理了,只是Activity会负责整个视图的生命周期。这个悬浮窗就是脱离了Activity的限制。
在这里我们设置了系统窗口类型,只是系统管制了,需要手动设置权限而已。
一个Activity里有一个Window对象,这个Window对象就包含了布局,这个Window对象必须依附Activity,我们添加Dialog的时候其实就是加一个Window对象,所以我们在新建Dialog的时候不能传Context,而必须传Activity实例对象的原因。
像我们的事件分发机制,为什么是Activity–>ViewGroup–>View的流程,也就有了答案,因为点击事件是由底层硬件发出的,而Activity是我们承载布局的组件(中间件),从底层往上传递,肯定是Activity在前面。
Android悬浮窗相关推荐
- android悬浮窗语音识别demo
带有android悬浮窗的语音识别语义理解demo 如发现代码排版问题,请访问CSDN博客 Android桌面悬浮窗实现比较简单,本篇以一个语音识别,语义理解的demo来演示如何实现android悬浮 ...
- Android 悬浮窗功能的实现
前言 我们大多数在两种情况下可以看到悬浮窗,一个是视频通话时的悬浮窗,另一个是360卫士的悬浮球,实现此功能的方式比较多,这里以视频通话悬浮窗中的需求为例.编码实现使用Kotlin.Java版本留言邮 ...
- Android悬浮窗的简单实现
1. 前言 现在很多应用都有小悬浮窗的功能,比如看直播的时候,通过Home键返回桌面,直播的小窗口仍可以在屏幕上显示.下面将介绍下悬浮窗的的一种简单实现方式. 2.原理 Window我们应该很熟悉,它 ...
- Android悬浮窗的实现
Android悬浮窗的实现 *本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 本文也发布于本人的知乎文章:https://zhuanlan.zhihu.com/p/39421112 ...
- Android悬浮窗原理解析(Window)[源码]
悬浮窗,在大多数应用中还是很少见的,目前我们接触到的悬浮窗,差不多都是一些系统级的应用软件,例如:360安全卫士,腾讯手机管家等:在某些服务行业如金融,餐饮等,也会在应用中添加悬浮窗,例如:美团的偷红 ...
- 安卓java浮层不响应点击事件,Android悬浮窗屏蔽悬浮窗外部所有的点击事件的实例代码...
Android可以在所有应用上方添加View,就是给WindowManager添加一个View,在创建的View的时候可以给这个View设置LayoutParams(android.view.Wind ...
- Android展开悬浮窗功能,Android 悬浮窗 (附圆形菜单悬浮窗)
序言 Android悬浮窗的实现,主要有四个步骤: 1. 声明及申请权限 2. 构建悬浮窗需要的控件 3. 将控件添加到WindowManager 4. 必要时更新WindowManager的布局 一 ...
- android动态获取悬浮窗,Android 悬浮窗实现
Android悬浮窗实现中需要注意的两点是 1.Android 6.0之后的悬浮窗动态申请 2.Window 的type属性在Android8.0前后的适配 public abstract class ...
- Android悬浮窗适配全机型,包含8.0,小米魅族华为悬浮窗权限适配demo看这一篇就够了
机型多杂,适配无法完全兼容,不如换种实现方式,性能比悬浮窗好,不需要权限,效果更好:https://blog.csdn.net/m0_38058826/article/details/10399339 ...
- Android悬浮窗开启 适配所有机型(附源码)
Android悬浮窗开启 适配所有机型(附源码) 1.开启悬浮窗权限 清单文件中添加: <uses-permission android:name="android.permissio ...
最新文章
- LiFi会将大数据和物联网带到新高度吗?
- v-for 切换不同的class
- html中怎么选择相同的代码,不同的HTML,相同的代码隐藏和相同的控件
- insert事务隔离mysql_MySQL数据库详解(三)MySQL的事务隔离剖析
- Feature Engineering 特征工程 3. Feature Generation
- mysql 中序号要怎么写_如何在mysql的字段ID中插入自动编号?
- 1.2. Cisco IOS Firewall
- Python爬虫的智能化解析——Diffbot
- 机器学习基石笔记-Lecture 14 Regularization
- 【转】ASPNET程序中常用的三十三种代码
- fiddler 查看接口响应时间
- 2022年第十三届蓝桥杯省赛--难度评价
- 10款提高工作效率的工具软件,你值得拥有!
- 卷积神经网络学习路线(十九) | 旷世科技 2017 ShuffleNetV1
- 红牛v5 android cm12.1 分辨率修改
- SQL之to_date()
- dll注册加载失败解决方法
- 湖南云畅网络科技有限公司携手伙伴,共筑长三角数字经济产业新高地
- mysql求每个班级的最高分_sql查询每个班上成绩最高的学生信息
- c语言字母转换数字代码,实现c语言中字符串和数字的相互转换的代码
热门文章
- GitHub标星1w的安卓架构师必备技能,终获offer
- 农场游戏开发记录十七(控制台版本完成)
- python好用的库存尾货女装_服装库存尾货生意怎么做?
- JS 基础交互(交互三部曲)
- 【paper】VPGNet 论文浅析
- qq空间个人档html代码,qq空间个人档签名
- imp-00017: 由于 oracle 错误 6550,数据库IMP导入时常见错误说明-转自百度空间-三生有约...
- ACREL-3000电能管理系统在金桥德勤电能管理系统项目中的应用
- 凭这份Java面试宝典,我成功拿到阿里、腾讯、百度、字节等六家大厂offer!
- 《仙剑奇侠传三》游戏分析