Android悬浮窗 Android创建悬浮窗的完整步骤
HackShendi 人气:0想了解Android创建悬浮窗的完整步骤的相关内容吗,HackShendi在本文为您仔细讲解Android悬浮窗的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:android悬浮窗开发,android悬浮窗源码,android悬浮窗实现,下面大家一起来学习吧。
在Android中想要创建悬浮窗分为三步
1.申请权限
2.使用服务启动悬浮窗
3.设置悬浮窗参数并添加进WindowManager
下面话不多说了,来一起看看详细的实现过程
申请权限
首先需要申请悬浮窗权限,在清单文件中 manifest 下添加
<!-- 低版本悬浮窗所需权限 --> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
在Activity中动态申请权限
public class MainActivity extends Activity { /** 悬浮窗权限标识码 */ public static final int CODE_WINDOW = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 申请悬浮窗权限 if (Build.VERSION.SDK_INT >= 23) { if (!Settings.canDrawOverlays(this)) { Toast.makeText(this, "请打开此应用悬浮窗权限-Shendi", Toast.LENGTH_SHORT).show(); startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), CODE_WINDOW); } } // 关闭当前activity,这样只显示悬浮窗 finish(); } // 权限申请成功后的回调 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { // 不给权限就退出 case Permission.CODE_WINDOW: if (resultCode != Activity.RESULT_OK) System.exit(0); break; default: Toast.makeText(this, "未知权限回调: " + requestCode, Toast.LENGTH_SHORT).show(); } } }
使用服务启动悬浮窗
对于悬浮窗的操作主要使用 WindowManager
创建一个服务,并在清单文件中注册
public class TestService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent intent) { return null; } }
在清单文件的Application中注册服务
<service android:name=".TestService" />
在Activity中启动服务
Intent intent = new Intent(this, TestService.class); startService(intent);
接下来需要创建悬浮窗的界面,这里方便演示直接使用代码创建
也可以使用inflate函数将xml文件变view对象
View.inflate(context, R.layout.main_activity, null);
在服务的onStartCommand函数中内容如下
@Override public int onStartCommand(Intent intent, int flags, int startId) { Button btn = new Button(this); btn.setText("hello,world"); return super.onStartCommand(intent, flags, startId); }
设置悬浮窗参数并添加进WindowManager
这里直接上代码,看注释
@Override public int onStartCommand(Intent intent, int flags, int startId) { Button btn = new Button(this); btn.setText("hello,world"); // 获取WindowManager WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); // 创建布局参数 WindowManager.LayoutParams params = new WindowManager.LayoutParams(); /** 设置参数 */ params.type = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY : WindowManager.LayoutParams.TYPE_PHONE; params.format = PixelFormat.RGBA_8888; // 设置窗口的行为准则 params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; //设置透明度 params.alpha = 1.0f; //设置内部视图对齐方式,这边位置为左边靠上 params.gravity = Gravity.LEFT | Gravity.TOP; //窗口的左上角坐标 params.x = 0; params.y = 0; //设置窗口的宽高,这里为自动 params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.height = WindowManager.LayoutParams.WRAP_CONTENT; // 添加进WindowManager wm.addView(btn, params); return super.onStartCommand(intent, flags, startId); }
完整代码如下
TestActivity
package shendi.app.game.robot; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.widget.Toast; public class TestActivity extends Activity { /** 悬浮窗权限标识码 */ public static final int CODE_WINDOW = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 申请悬浮窗权限 if (Build.VERSION.SDK_INT >= 23) { if (!Settings.canDrawOverlays(this)) { Toast.makeText(this, "请打开此应用悬浮窗权限-Shendi", Toast.LENGTH_SHORT).show(); startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), CODE_WINDOW); } } Intent intent = new Intent(this, TestService.class); startService(intent); // 关闭当前activity,这样只显示悬浮窗 finish(); } // 权限申请成功后的回调 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { // 不给权限就退出 case Permission.CODE_WINDOW: if (resultCode != Activity.RESULT_OK) System.exit(0); break; default: Toast.makeText(this, "未知权限回调: " + requestCode, Toast.LENGTH_SHORT).show(); } } }
TestService
package shendi.app.game.robot; import android.app.Service; import android.content.Intent; import android.graphics.PixelFormat; import android.os.Build; import android.os.IBinder; import android.view.Gravity; import android.view.WindowManager; import android.widget.Button; public class TestService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { Button btn = new Button(this); btn.setText("hello,world"); // 获取WindowManager WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); // 创建布局参数 WindowManager.LayoutParams params = new WindowManager.LayoutParams(); /** 设置参数 */ params.type = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY : WindowManager.LayoutParams.TYPE_PHONE; params.format = PixelFormat.RGBA_8888; // 设置窗口的行为准则 params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; //设置透明度 params.alpha = 1.0f; //设置内部视图对齐方式,这边位置为左边靠上 params.gravity = Gravity.LEFT | Gravity.TOP; //窗口的左上角坐标 params.x = 0; params.y = 0; //设置窗口的宽高,这里为自动 params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.height = WindowManager.LayoutParams.WRAP_CONTENT; // 添加进WindowManager wm.addView(btn, params); return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent intent) { return null; } }
运行 app,可以在屏幕左上角看到 hello,world的按钮悬浮
拖动效果
给悬浮组件添加触碰事件可以实现拖动效果,按钮组件不适用
这里给出简单的实现代码片段
private int upX, upY; // 视图移动处理 view.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: upX = (int) event.getRawX(); upY = (int) event.getRawY(); break; case MotionEvent.ACTION_MOVE: // 与上一次位置相差不到5则不移动 if (event.getRawX() - upX > 5 || event.getRawY() - upY > 5) { params.x = (int) event.getRawX(); params.y = (int) event.getRawY(); wm.updateViewLayout(view, params); } break; case MotionEvent.ACTION_UP: // 相差不到5则代表点击 if (event.getRawX() - upX < 5 && event.getRawY() - upY < 5) { // TODO } break; } return false; } });
移除悬浮窗
可以在 onDestry 函数中进行移除
@Override public void onDestroy() { wm.removeView(view); super.onDestroy(); }
总结
加载全部内容