详解android6.0版本下悬浮窗实现
作者:迟做总比不做强 发布时间:2023-09-04 18:43:34
标签:android,悬浮窗
悬浮窗在安卓中实现起来还是比较容易的,这几天在网上温习了相关资料,运行在我安卓6.0手机上才发现,原来在6.0手机上不是行的。
第一反应肯定是权限相关问题,做了相关处理后,果然让悬浮窗原形毕露了。直接贴代码。
public class MainActivity extends AppCompatActivity {
private static final int ALERT_WINDOW_PERMISSION_CODE = 100;
private Button start_float;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start_float = (Button) findViewById(R.id.start_float);
this.start_float.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (Build.VERSION.SDK_INT > 22) {
sdk23Permission();
} else {
startService(new Intent(MainActivity.this, FloatService.class));
finish();
}
}
});
}
/**
* @description 安卓6.0下权限处理
* @author ldm
* @time 2017/3/20 15:00
*/
public void sdk23Permission() {
if (!Settings.canDrawOverlays(this)) {
Toast.makeText(MainActivity.this, "当前无权限使用悬浮窗,请授权!", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, ALERT_WINDOW_PERMISSION_CODE);
} else {
startService(new Intent(MainActivity.this, FloatService.class));
finish();
}
}
/**
* 用户返回
*/
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ALERT_WINDOW_PERMISSION_CODE) {
if (!Settings.canDrawOverlays(this)) {
Toast.makeText(MainActivity.this, "权限授予失败,无法开启悬浮窗", Toast.LENGTH_SHORT).show();
} else {
startService(new Intent(MainActivity.this, FloatService.class));
finish();
}
}
}
}
对应Service:
public class FloatService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
FloatViewUtils.getInstance(this).addFloatView();
super.onCreate();
}
}
简单地FloatView:
public class FloatView extends View {
public static final int WIDTH = 150;
public static final int HEIGHT = 150;
private Paint circlePaint;
private Paint textPaint;
private static final String text = "50%";
public FloatView(Context context) {
this(context, null, 0);
}
public FloatView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public FloatView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaints();
}
/**
* @description 初始化相关画笔Paint
* @author ldm
* @time 2017/3/20
*/
private void initPaints() {
circlePaint = new Paint();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.GRAY);
textPaint = new Paint();
//设置抗锯齿
textPaint.setAntiAlias(true);
//设置字体大小
textPaint.setTextSize(30);
//设置颜色
textPaint.setColor(Color.WHITE);
//设置(仿)粗体
textPaint.setFakeBoldText(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(WIDTH, HEIGHT);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(WIDTH / 2, HEIGHT / 2, WIDTH / 2, circlePaint);
float textWidth = textPaint.measureText(text);
float x = WIDTH / 2 - textWidth / 2;
Paint.FontMetrics fms = textPaint.getFontMetrics();
float dy = -(fms.descent + fms.ascent) / 2;
float y = HEIGHT / 2 + dy;
canvas.drawText(text, x, y, textPaint);
}
}
以及FloatView管理工具类:
public class FloatViewUtils {
private static FloatViewUtils instance;
private Context mContext;
private WindowManager manager;
private FloatView floatView;
private FloatViewUtils(Context mContext) {
this.mContext = mContext;
manager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
floatView = new FloatView(mContext);
}
public static FloatViewUtils getInstance(Context mContext) {
if (null == instance) {
synchronized (FloatViewUtils.class) {
if (null == instance) {
instance = new FloatViewUtils(mContext);
}
}
}
return instance;
}
public void addFloatView() {
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
//悬浮窗口大小
lp.width = floatView.WIDTH;
lp.height = floatView.HEIGHT;
// 调整悬浮窗口位置
lp.gravity = Gravity.LEFT | Gravity.CENTER;
// 以屏幕左上角为原点,设置x、y初始值
// lp.x = 0;
// lp.y = 0;
//设置悬浮窗口类型
lp.type = WindowManager.LayoutParams.TYPE_PHONE;
//设置悬浮窗口不接受焦点及触摸事件
lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
//设置图片格式,效果为背景透明
lp.format = PixelFormat.RGBA_8888;
manager.addView(floatView, lp);
}
}
最后不要忘记在AndroidManifest.xml中添加权限(当然还有注册Service):
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
来源:http://blog.csdn.net/true100/article/details/64126121


猜你喜欢
- 一、流程和任务的关系以下是一个简单的请假流程图,其中有一个开始事件,两个用户任务,一个结束事件。启动流程后,activiti会自动创建第一个
- spinner组件有点类型于HTML中的下拉框<Select></select>的样子,让用户每次从下拉框中选取一个
- •android-support-v4.jar,这是谷歌官方给我们提供的一个兼容低版本Android设备的软件包,里面包囊了只有在Andro
- 一直做Android前端,今天突然心血来潮想搭建一个后台玩玩。平时都是需要什么样的接口直接出个接口文档扔给后台的兄弟,自己从来不操心他们内部
- 一、问题场景使用Logger.error方法时只能打印出异常类型,无法打印出详细的堆栈信息,使得定位问题变得困难和不方便。二、先放出结论Lo
- 前言空间分配要点有:一是空间分配的连续性;二是动态内存申请;三是防止程序执行中出现异常错误。提示:开始讲解了嗷~后续会根据精力持续更新嗷!!
- 现在版本更新有两种处理方式:跳转到App应用市场,通过应用市场下载更新安装。在App内进行Apk下载,下载完成后更新安装。实现思路:请求后台
- 一、cancel()无效当协程任务被取消的时候,它的内部是会产生一个 CancellationException 的。而协程的结构化并发,最
- 缘由首先说明一下为什么会有这篇文章。前段时间,插件化以及热修复的技术很热,Nuwa热修复的工具NuwaGradle,携程动态加载技术Dyna
- 这篇文章主要介绍了JDK线程池和Spring线程池的使用实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值
- DES一共就有4个参数参与运作:明文、密文、密钥、向量。为了初学者容易理解,可以把4个参数的关系写成:密文=明文+密钥+向量;明文=密文-密
- 一、this可以代表引用类的当前实例,包括继承而来的方法,通常可以省略。public class Person{ &n
- 项目比较大有时候会比较卡,虽然有GC自动清理机制,但是还是有不尽人意的地方。所以尝试在项目启动文件中,手动写了一个定时器,定时清理内存,加快
- Java中可以使用关键字synchronized进行线程同步控制,实现关键资源顺序访问,避免由于多线程并发执行导致的数据不一致性等问题。sy
- 一. 简介 SQLite数据库是一个轻量级的DBMS(数据库管理系统)。SQLite使用单个文件存储数据,Android标准库包含SQLit
- 接口回调是指:可以把使用某一接口的类创建的对象的引用赋给该接口声明的接口变量,那么该接口变量就可以调用被类实现的接口的方法。实际上,当接口变
- 一开始我就纳闷了,怎么调试都只是一个光溜溜的界面,右侧的工具栏都没有如图:就一个光秃秃的界面,什么都没有,这就对调试很不方便于是我就试了试各
- 之前不怎么了解这个,一直以为做起来很复杂。 直到前两天公司要求要做这个功能。 做了之后才发现 这不过就是一个POST请求就能实现的东西。现在
- 一内容:设计一个手写字体识别程序。二实现①建立一个存放手写字体的数据库②activity_main.xml<?xml version=
- AlertDialog的几种用法xml代码:<?xml version="1.0" encoding="