在 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 方法中移除浮窗视图,避免内存泄漏。
相关推荐
CYRUS_STUDIO5 分钟前
Frida Hook Native:jobjectArray 参数解析
android·c++·逆向
pengyu1 小时前
系统化掌握Dart网络编程之Dio(二):配置管理篇
android·flutter·dart
Yang-Never2 小时前
Open GL ES ->纹理贴图,顶点坐标和纹理坐标组合到同一个顶点缓冲对象中进行解析
android·java·开发语言·android studio·贴图
a3158238062 小时前
SnapdragonCamera骁龙相机源码解析
android·数码相机·framework·高通
IT乐手2 小时前
adb logcat 写文件乱码的解决方案
android·python
xiaoduyyy3 小时前
【Android】View动画—XML动画、帧动画
android·xml
weixin_454102463 小时前
cordova android12+升级一些配置注意事项
android·前端·cordova
兰亭序咖啡4 小时前
学透Spring Boot — 007. 加载外部配置
android·java·spring boot
8931519605 小时前
Android穿山甲banner广告穿插到项目的banner中
android·android开发·android教程·穿山甲banner广告加入项目
利明的博客5 小时前
mediacodec服务启动时加载media_codecs.xml
android·xml·java