赞
踩
悬浮窗是可以在不同软件最上面,默认的效果,不需要过多设置,通常放在服务里面,因为需要长时间存在
写一个悬浮窗大概是以下几个步骤
1、写一个服务,因为悬浮窗长期存在,不依赖于界面,所有最好写在服务里面。
2、在服务需要获取到WindowManager这个类,用来加载一个悬浮窗的布局和一些列点击事件。
3、启动服务,悬浮窗就可以启动。
1、悬浮窗的穿透点击
当悬浮窗悬浮的时候,理想状态,应该是悬浮窗里面的按钮和悬浮窗底层点击触摸事件不冲突。
2、需要注意,悬浮窗的可能会出现黑色背景,需要加params.format = PixelFormat.RGBA_8888;
1、写一个服务
public class BackService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }
2、在服务里面写一个一个方法,去创建一个一个悬浮窗的样式
/** * 初始化一个悬浮窗 */ private void initWindow() { // 获取WindowManager mSystemService = (WindowManager) getSystemService(WINDOW_SERVICE); // 创建布局参数 WindowManager.LayoutParams params = new WindowManager.LayoutParams(); //这里需要进行不同的设置 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { params.type = WindowManager.LayoutParams.TYPE_PHONE; } //设置透明度 params.alpha = 1.0f; //设置内部视图对齐方式 params.gravity = Gravity.RIGHT | Gravity.BOTTOM; //窗口的右上角角坐标 params.x = 20; params.y = 20; //是指定窗口的像素格式为 RGBA_8888。 //使用 RGBA_8888 像素格式的窗口可以在保持高质量图像的同时实现透明度效果。 params.format = PixelFormat.RGBA_8888; //设置窗口的宽高,这里为自动 params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.height = WindowManager.LayoutParams.WRAP_CONTENT; //这段非常重要,是后续是否穿透点击的关键 params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE //表示悬浮窗口不需要获取焦点,这样用户点击悬浮窗口以外的区域,就不需要关闭悬浮窗口。 |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;//表示悬浮窗口不会阻塞事件传递,即用户点击悬浮窗口以外的区域时,事件会传递给后面的窗口处理。 //这里的引入布局文件的方式,也可以动态添加控件 mView = View.inflate(getApplicationContext(), R.layout.item_back, null); Button btnBack = mView.findViewById(R.id.btn_back); mSystemService.addView(mView,params); }
ps:此处要注意一下,当服务销毁的时候,需要记得,把布局的view给removeView
@Override
public void onDestroy() {
super.onDestroy();
if (mSystemService != null && mView != null){
mSystemService.removeView(mView);
}
}
3、启动服务,悬浮窗就可以启动
startService(new Intent(context, BackService.class));
1、需要注意在悬浮窗的点击中,需要效果是悬浮窗里面的按钮和悬浮窗底层点击触摸事件不冲突,关键代码是这儿
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE //表示悬浮窗口不需要获取焦点,这样用户点击悬浮窗口以外的区域,就不需要关闭悬浮窗口。
|WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;//表示悬浮窗口不会阻塞事件传递,即用户点击悬浮窗口以外的区域时,事件会传递给后面的窗口处理。
2、悬浮窗如果出现黑色背景,必须加这儿
//是指定窗口的像素格式为 RGBA_8888。
//使用 RGBA_8888 像素格式的窗口可以在保持高质量图像的同时实现透明度效果。
params.format = PixelFormat.RGBA_8888;
3、如果要隐藏当前的avtivity,只有悬浮窗,可以通过moveTaskToBack(true);
设置
当activity的启动模式是singleInstance的时候,在当前的activity直接调用moveTaskToBack(true),即可将activity 退到后台
参数说明:
参数为false——代表只有当前activity是task根,指应用启动的第一个activity时,才有效;
参数为true——则忽略这个限制,任何activity都可以有效。
设置avtivity启动模式在AndroidManifest里面
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:exported="true"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
服务里面,启动服务很简单
public class BackService extends Service { private View mView; private WindowManager mSystemService; @Override public int onStartCommand(Intent intent, int flags, int startId) { initWindow(); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); if (mSystemService != null && mView != null){ mSystemService.removeView(mView); } } /** * 初始化一个悬浮窗 */ private void initWindow() { // 获取WindowManager mSystemService = (WindowManager) getSystemService(WINDOW_SERVICE); // 创建布局参数 WindowManager.LayoutParams params = new WindowManager.LayoutParams(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { params.type = WindowManager.LayoutParams.TYPE_PHONE; } //设置透明度 params.alpha = 1.0f; //设置内部视图对齐方式 params.gravity = Gravity.RIGHT | Gravity.BOTTOM; //窗口的左上角坐标 params.x = 20; params.y = 20; //是指定窗口的像素格式为 RGBA_8888。 //使用 RGBA_8888 像素格式的窗口可以在保持高质量图像的同时实现透明度效果。 params.format = PixelFormat.RGBA_8888; //设置窗口的宽高,这里为自动 params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.height = WindowManager.LayoutParams.WRAP_CONTENT; params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE //表示悬浮窗口不需要获取焦点,这样用户点击悬浮窗口以外的区域,就不需要关闭悬浮窗口。 |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;//表示悬浮窗口不会阻塞事件传递,即用户点击悬浮窗口以外的区域时,事件会传递给后面的窗口处理。 mView = View.inflate(getApplicationContext(), R.layout.item_back, null); Button btnBack = mView.findViewById(R.id.btn_back); btnBack.setOnClickListener(view1 -> { ToastUtils.showShort("点击了");//此处是点击逻辑,可以自己完成 }); mSystemService.addView(mView,params); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
一、面试合集
二、源码解析合集
三、开源框架合集
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。