【Android】创建一个可以在屏幕上拖动的悬浮窗

项目需求

在界面上创建一个悬浮窗,可以自由的移动这个悬浮窗

需求解决

1.添加权限

java 复制代码
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

2.请求权限

从 Android 6.0 (API 23) 开始,应用需要动态请求显示悬浮窗的权限。例如,可以在 MainActivity 中请求权限:

java 复制代码
public class MainActivity extends AppCompatActivity {

    private static final int OVERLAY_PERMISSION_REQUEST_CODE = 1234;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!Settings.canDrawOverlays(this)) {
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                        Uri.parse("package:" + getPackageName()));
                startActivityForResult(intent, OVERLAY_PERMISSION_REQUEST_CODE);
            } else {
                // 权限已经授予,启动悬浮窗服务
                startFloatingWindowService();
            }
        } else {
            // 系统版本低于6.0,不需要请求权限,直接启动悬浮窗服务
            startFloatingWindowService();
        }

    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == OVERLAY_PERMISSION_REQUEST_CODE) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (Settings.canDrawOverlays(this)) {
                    // 权限授予,启动悬浮窗服务
                    startFloatingWindowService();
                } else {
                    // 权限未授予,提示用户
                    // TODO: 处理权限未授予情况
                }
            }
        }
    }


    private void startFloatingWindowService() {
        Intent intent = new Intent(MainActivity.this, FloatingWindowService.class);
        startService(intent);
    }
}
  1. 创建悬浮窗服务
    实现一个服务(FloatingWindowService),它将负责创建和管理悬浮窗视图。
java 复制代码
public class FloatingWindowService extends Service {


    private WindowManager windowManager;
    private View floatingView;

    public FloatingWindowService() {
    }


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);

        floatingView = inflater.inflate(R.layout.floating_window, null);

        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT);

        // 初始位置
        params.x = 0;
        params.y = 0;

        windowManager.addView(floatingView, params);

        // 使悬浮窗可拖动
        floatingView.setOnTouchListener(new View.OnTouchListener() {
            private int initialX;
            private int initialY;
            private float initialTouchX;
            private float initialTouchY;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        initialX = params.x;
                        initialY = params.y;
                        initialTouchX = event.getRawX();
                        initialTouchY = event.getRawY();
                        return true;
                    case MotionEvent.ACTION_MOVE:
                        params.x = initialX + (int) (event.getRawX() - initialTouchX);
                        params.y = initialY + (int) (event.getRawY() - initialTouchY);
                        windowManager.updateViewLayout(floatingView, params);
                        return true;
                }
                return false;
            }
        });
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (floatingView != null) windowManager.removeView(floatingView);
    }
}
  1. 创建悬浮窗布局
    在 res/layout 目录下创建一个名为 floating_window.xml 的布局文件:
java 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#80000000"
    android:orientation="vertical"
    android:padding="10dp">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="CSDN -> 我又来搬代码了"
        android:textColor="#FFFFFF" />

</LinearLayout>

注意:要记得在注册清单文件注册服务

java 复制代码
        <service
            android:name=".service.FloatingWindowService"
            android:enabled="true"
            android:exported="true" />

实现效果

这个可以随意拖动。

相关推荐
恋猫de小郭30 分钟前
罗技鼠标因为服务器证书过期无法使用?我是如何解决 SSL 证书问题
android·前端·flutter
yongui4783437 分钟前
MATLAB中回归模型常用误差指标(MSE、RMSE、MAPE等)的实现方法
android·matlab·回归
莫比乌斯环1 小时前
【Android技能点】启动链路 + AMS/ATMS 基础概念掌握
android
AKA1 小时前
Android中第三方库的使用
android
城东米粉儿1 小时前
Android音视频开发基础知识指南
android
莫比乌斯环1 小时前
【Android技能点】一张图理清 开机、App启动流程
android
我命由我123452 小时前
Android Jetpack Compose - Compose 重组、AlertDialog、LazyColumn、Column 与 Row
android·java·java-ee·kotlin·android studio·android jetpack·android-studio
愤怒的代码2 小时前
在 Android 中执行 View.invalidate() 方法后经历了什么
android·java·kotlin
PoppyBu3 小时前
Ubuntu20.04版本上安装最新版本的scrcpy工具
android·ubuntu
执念、坚持4 小时前
Property Service源码分析
android