赞
踩
全局悬浮窗在许多应用中都能见到,点击Home键,小窗口仍然会在屏幕上显示。如微信视频,360软件清理等等,在此记录一下实现代码。
悬浮窗要能够全局显示就必须要申请权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
tools:ignore="ProtectedPermissions" />
当API Level>=23的时候就要动态的申请权限了,判断是否能够绘制悬浮窗:
Settings.canDrawOverlays(this)
返回为true就表明已同意权限,否则就表示没有全局绘制的权限。此处获取权限需要跳转设置用户手动打开:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT);
Intent intent = new Intent();
intent.setAction(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 0);
}
全局的悬浮窗是通过WindowManager来绘制已达到能够全局显示的效果,而WindowManager的addView方法还需要一个WindowManager.LayoutParam对象作为参数,此处Android 8.0之后的需要适配一下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}
为了能够使悬浮窗脱离activity全局显示,因此这里使用Service来启动悬浮窗。
界面触发悬浮窗代码如下:
public class MainActivity extends AppCompatActivity { public static boolean isStart = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btFloatingWindow = findViewById(R.id.bt_floating_window); btFloatingWindow.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startFloatingService(); } }); } @SuppressLint("ShowToast") public void startFloatingService() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) { Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT); Intent intent = new Intent(); intent.setAction(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); intent.setData(Uri.parse("package:" + getPackageName())); startActivityForResult(intent, 0); return; } if (!isStart) { startService(new Intent(MainActivity.this, FloatingService.class)); } } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 0) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) { Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show(); if (!isStart) startService(new Intent(MainActivity.this, FloatingService.class)); } } } }
创建悬浮窗的服务代码如下
public class FloatingService extends Service { private WindowManager windowManager; private WindowManager.LayoutParams layoutParams; @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { showFloatingWindow(); return super.onStartCommand(intent, flags, startId); } @SuppressLint("InflateParams") private void showFloatingWindow() { MainActivity.isStart = true; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(this)) { // 获取WindowManager服务 windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); // 设置LayoutParam 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.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; //宽高自适应 layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; //显示的位置 layoutParams.x = 300; layoutParams.y = 300; // 新建悬浮窗控件 View view = LayoutInflater.from(this).inflate(R.layout.float_window, null); view.setOnTouchListener(new FloatingOnTouchListener()); // 将悬浮窗控件添加到WindowManager windowManager.addView(view, layoutParams); } } private class FloatingOnTouchListener implements View.OnTouchListener { private int x; private int y; @SuppressLint("ClickableViewAccessibility") @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; } } @Override public void onDestroy() { super.onDestroy(); MainActivity.isStart = false; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。