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

实现效果

这个可以随意拖动。

相关推荐
Cutecat_1 小时前
视频字幕处理工具横向:提取模式 vs 编辑模式,该如何选择
android·前端·ios·语音识别
2601_961765292 小时前
【分享】PlayerPro媒体音乐播放器 完整专业版
android·媒体
JohnnyDeng944 小时前
【Android】Android 包体积优化:R8/ProGuard 深度配置全攻略
android·性能优化·kotlin·jetpack
故渊at4 小时前
第九板块:Android 多媒体体系 | 第二十四篇:Camera Service 与 HAL3 成像流水线
android·camera·多媒体体系·hal3
Jinkxs8 小时前
Python基础 - 初识内置函数 Python自带的便捷工具
android·java·python
私人珍藏库8 小时前
【Android】VLLO-韩国热门手机剪辑APP
android·app·工具·软件·多功能
Cloud_Shy6189 小时前
解读《Effective Python 3rd Edition》:从练气到老魔(第六章 Item 40 - 43)
android·开发语言·人工智能·笔记·python·学习方法
AFinalStone9 小时前
Android12 U盘插拔链路源码全解析(五):Framework层(下) StorageManagerService
android·frameworks
林九生11 小时前
【实用技巧】MySQL 绿色版一键路径更新脚本详解 —— update_path.bat 深度解析
android·数据库·mysql
故渊at12 小时前
第十三板块:Android 综合架构与未来演进 | 第三十一篇:Android 架构演进与 Fuchsia OS 的挑战
android·架构·宏内核·微内核·fuchsia·ipc 性能博弈