在 Android 中实现浮窗(悬浮窗)并添加吸边效果

在 Android 中实现浮窗(悬浮窗)并添加吸边效果,可以使用 WindowManager 来管理浮窗视图,并通过触摸事件来实现吸边效果。以下是一个示例,展示如何创建一个浮窗并实现吸边效果。

1. 添加权限

首先,确保您的应用具有显示悬浮窗的权限。在 AndroidManifest.xml 文件中添加以下权限:

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

2. 请求悬浮窗权限

在 Android 6.0(API 级别 23)及更高版本中,您需要在运行时请求悬浮窗权限:

java 复制代码
import android.content.Intent;

import android.net.Uri;

import android.os.Build;

import android.os.Bundle;

import android.provider.Settings;

import androidx.annotation.Nullable;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private static final int REQUEST_CODE_OVERLAY_PERMISSION = 1001;

    @Override

    protected void onCreate(@Nullable 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, REQUEST_CODE_OVERLAY_PERMISSION);

            } else {

                // 已获得权限,显示浮窗

                showFloatingWindow();

            }

        } else {

            // 低于 Android 6.0,直接显示浮窗

            showFloatingWindow();

        }

    }

    @Override

    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {

        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == REQUEST_CODE_OVERLAY_PERMISSION) {

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

                if (Settings.canDrawOverlays(this)) {

                    // 已获得权限,显示浮窗

                    showFloatingWindow();

                }

            }

        }

    }

    private void showFloatingWindow() {

        // 显示浮窗的代码

    }

}

3. 创建浮窗并实现吸边效果

以下是一个完整的示例,展示如何创建一个浮窗并实现吸边效果:

java 复制代码
import android.content.Context;

import android.graphics.PixelFormat;

import android.os.Build;

import android.os.Bundle;

import android.view.Gravity;

import android.view.MotionEvent;

import android.view.View;

import android.view.WindowManager;

import android.widget.ImageView;

import androidx.annotation.Nullable;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private WindowManager windowManager;

    private WindowManager.LayoutParams layoutParams;

    private ImageView floatingView;

    @Override

    protected void onCreate(@Nullable 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, 1001);

            } else {

                showFloatingWindow();

            }

        } else {

            showFloatingWindow();

        }

    }

    @Override

    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {

        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == 1001) {

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

                if (Settings.canDrawOverlays(this)) {

                    showFloatingWindow();

                }

            }

        }

    }

    private void showFloatingWindow() {

        windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);

        floatingView = new ImageView(this);

        floatingView.setImageResource(R.drawable.ic_launcher_foreground); // 替换为您的图标

        layoutParams = new WindowManager.LayoutParams(

                WindowManager.LayoutParams.WRAP_CONTENT,

                WindowManager.LayoutParams.WRAP_CONTENT,

                Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?

                        WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :

                        WindowManager.LayoutParams.TYPE_PHONE,

                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,

                PixelFormat.TRANSLUCENT

        );

        layoutParams.gravity = Gravity.TOP | Gravity.LEFT;

        layoutParams.x = 0;

        layoutParams.y = 100;

        windowManager.addView(floatingView, layoutParams);

        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 = layoutParams.x;

                        initialY = layoutParams.y;

                        initialTouchX = event.getRawX();

                        initialTouchY = event.getRawY();

                        return true;

                    case MotionEvent.ACTION_MOVE:

                        layoutParams.x = initialX + (int) (event.getRawX() - initialTouchX);

                        layoutParams.y = initialY + (int) (event.getRawY() - initialTouchY);

                        windowManager.updateViewLayout(floatingView, layoutParams);

                        return true;

                    case MotionEvent.ACTION_UP:

                        int screenWidth = getResources().getDisplayMetrics().widthPixels;

                        if (layoutParams.x < screenWidth / 2) {

                            layoutParams.x = 0;

                        } else {

                            layoutParams.x = screenWidth;

                        }

                        windowManager.updateViewLayout(floatingView, layoutParams);

                        return true;

                }

                return false;

            }

        });

    }

    @Override

    protected void onDestroy() {

        super.onDestroy();

        if (floatingView != null) {

            windowManager.removeView(floatingView);

        }

    }

}

解释

  1. 请求悬浮窗权限 :在 onCreate 方法中检查并请求悬浮窗权限。
  2. 创建浮窗 :使用 WindowManager 创建浮窗,并设置 WindowManager.LayoutParams
  3. 实现吸边效果 :通过 setOnTouchListener 方法监听浮窗的触摸事件,在 ACTION_UP 事件中实现吸边效果。

注意事项

  • 权限管理:确保在 Android 6.0 及更高版本中正确请求悬浮窗权限。
  • 悬浮窗类型 :在 Android 8.0 及更高版本中,使用 WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY 类型。
  • 资源管理 :在 onDestroy 方法中移除浮窗视图,避免内存泄漏。
相关推荐
梓仁沐白19 分钟前
Android清单文件
android
董可伦3 小时前
Dinky 安装部署并配置提交 Flink Yarn 任务
android·adb·flink
每次的天空3 小时前
Android学习总结之Glide自定义三级缓存(面试篇)
android·学习·glide
恋猫de小郭3 小时前
如何查看项目是否支持最新 Android 16K Page Size 一文汇总
android·开发语言·javascript·kotlin
flying robot5 小时前
小结:Android系统架构
android·系统架构
xiaogai_gai5 小时前
有效的聚水潭数据集成到MySQL案例
android·数据库·mysql
鹅鹅鹅呢6 小时前
mysql 登录报错:ERROR 1045(28000):Access denied for user ‘root‘@‘localhost‘ (using password Yes)
android·数据库·mysql
在人间负债^6 小时前
假装自己是个小白 ---- 重新认识MySQL
android·数据库·mysql
Unity官方开发者社区6 小时前
Android App View——团结引擎车机版实现安卓应用原生嵌入 3D 开发场景
android·3d·团结引擎1.5·团结引擎车机版
进击的CJR9 小时前
MySQL 8.0 OCP 英文题库解析(三)
android·mysql·开闭原则