悬浮窗是在系统上显示的内容,好像微信视频聊天时的小窗口一样,在退出软件后依然存在的一个窗口,本博客以窗口中放一个button组件为例,简单展示悬浮窗,其中包括了对Android 6.0以下、Android 6.0到Android 8.0、Android 8.0以上版本的处理,下面开始介绍实现方法:
1、MainActivity中的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
public Button mFloatingButton; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); //初始化view initView(); } //初始化view private void initView() { mFloatingButton=(Button) findViewById(R.id.floating_btn); mFloatingButton.setOnClickListener( this ); } public void startFloatingButtonService(View view) { Log.e( "测试流程" , "测试流程" ); if (FloatingService_Button.isStarted) { Log.e( "测试流程2" , "测试流程2" ); return ; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { //判断系统版本 if (!Settings.canDrawOverlays( this )) { Toast.makeText( this , "当前无权限,请授权" , Toast.LENGTH_SHORT); Log.e( "测试流程3" , "测试流程3" ); startActivityForResult( new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse( "package:" + getPackageName())), 0 ); } else { Log.e( "测试流程4" , "测试流程4" ); startService( new Intent(MainActivity. this , FloatingService_Button. class )); } } else { startService( new Intent(MainActivity. this , FloatingService_Button. class )); } } @Override protected void onActivityResult( int requestCode, int resultCode, Intent data) { if (requestCode == 0 ) { if (!Settings.canDrawOverlays( this )) { Log.e( "测试流程5" , "测试流程5" ); Toast.makeText( this , "授权失败" , Toast.LENGTH_SHORT).show(); } else { Log.e( "测试流程6" , "测试流程6" ); Toast.makeText( this , "授权成功" , Toast.LENGTH_SHORT).show(); startService( new Intent(MainActivity. this , FloatingService_Button. class )); } } } @Override public void onClick(View v) { switch (v.getId()){ case R.id.floating_btn : startFloatingButtonService(v); break ; } } |
思路简单解释:点击弹出悬浮窗按钮时,获取版本并判断“Build.VERSION.SDK_INT >= Build.VERSION_CODES.M”如果系统版本在6.0以下这不需要请求权限,如果系统版本在6.0以上需要进行权限检测以及请求,获取权限后,弹出悬浮框
2、activity_main.xml代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" xmlns:tools = "http://schemas.android.com/tools" android:layout_width = "match_parent" android:layout_height = "match_parent" android:orientation = "vertical" tools:context = "com.example.jack_lin.suspendwindow.MainActivity" > < Button android:id = "@+id/floating_btn" style = "@style/floatingBtn" android:text = "@string/floating_btn" /> </ LinearLayout > |
简单解释:xml中没什么特别东西,线性布局中放一个按钮
3、FloatingService_Button的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
public static boolean isStarted = false ; private WindowManager windowManager; private WindowManager.LayoutParams layoutParams; private Button button; @Override public void onCreate() { super .onCreate(); Log.e( "进入服务1" , "进入服务1" ); isStarted = true ; windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); layoutParams = new WindowManager.LayoutParams(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE; } layoutParams.format = PixelFormat.RGBA_8888; layoutParams.gravity = Gravity.LEFT | Gravity.TOP; layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; layoutParams.width = 500 ; layoutParams.height = 100 ; layoutParams.x = 300 ; layoutParams.y = 300 ; } @Nullable @Override public IBinder onBind(Intent intent) { Log.e( "进入服务2" , "进入服务2" ); return null ; } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.e( "进入服务3" , "进入服务3" ); showFloatingWindow(); return super .onStartCommand(intent, flags, startId); } private void showFloatingWindow() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { //判断系统版本 if (Settings.canDrawOverlays( this )) { button = new Button(getApplicationContext()); button.setText( "我是个button窗口" ); button.setBackgroundColor(Color.BLUE); windowManager.addView(button, layoutParams); button.setOnTouchListener( new FloatingOnTouchListener()); } } else { button = new Button(getApplicationContext()); button.setText( "我是个button窗口" ); button.setBackgroundColor(Color.BLUE); windowManager.addView(button, layoutParams); button.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(view, layoutParams); break ; default : break ; } return false ; } } |
思路简单解释:首先获取WindowManager服务,然后定义并设置在window上显示的layoutParams(此处需注意Android 8.0以上版本中LayoutParam里的type变量变为TYPE_APPLICATION_OVERLAY与Android 8.0以下版本LayoutParam里的type变量TYPE_PHONE不一样,需要通过判断系统版本进行区分),然后定义并设置在layoutParams上面显示的Button按钮以及监听事件(此处的监听事件主要是悬浮窗口拖动的监听)最后将设置好的button与layoutParams添加入window中
4、AndroidManifest.xml中权限添加
1
2
|
< uses-permission android:name = "android.permission.SYSTEM_ALERT_WINDOW" /> < uses-permission android:name = "android.permission.INTERNET" /> |
5、效果图
源码下载地址:Android悬浮窗 源码下载
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/zhuchenglin830/article/details/81812747