在 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);
}
}
}
解释
- 请求悬浮窗权限 :在
onCreate
方法中检查并请求悬浮窗权限。 - 创建浮窗 :使用
WindowManager
创建浮窗,并设置WindowManager.LayoutParams
。 - 实现吸边效果 :通过
setOnTouchListener
方法监听浮窗的触摸事件,在ACTION_UP
事件中实现吸边效果。
注意事项
- 权限管理:确保在 Android 6.0 及更高版本中正确请求悬浮窗权限。
- 悬浮窗类型 :在 Android 8.0 及更高版本中,使用
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
类型。 - 资源管理 :在
onDestroy
方法中移除浮窗视图,避免内存泄漏。