【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" />

实现效果

这个可以随意拖动。

相关推荐
闲暇部落1 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
诸神黄昏EX3 小时前
Android 分区相关介绍
android
大白要努力!4 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee4 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
Winston Wood4 小时前
Perfetto学习大全
android·性能优化·perfetto
Dnelic-7 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记
Eastsea.Chen10 小时前
MTK Android12 user版本MtkLogger
android·framework
长亭外的少年17 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
建群新人小猿19 小时前
会员等级经验问题
android·开发语言·前端·javascript·php
1024小神20 小时前
tauri2.0版本开发苹果ios和安卓android应用,环境搭建和最后编译为apk
android·ios·tauri