📜  如何在Android中制作浮动窗口应用程序?(1)

📅  最后修改于: 2023-12-03 14:52:39.479000             🧑  作者: Mango

如何在Android中制作浮动窗口应用程序?

在Android应用程序中,想要实现浮动窗口,需要使用系统的WindowManager来创建一个浮动窗口。在本文中,将介绍如何使用WindowManager来创建浮动窗口应用程序。

创建浮动窗口的步骤
  1. 在AndroidManifest.xml文件中添加SYSTEM_ALERT_WINDOW权限。
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
  1. 新建一个Service,并在onCreate()方法中创建一个WindowManager对象。
public class FloatWindowService extends Service {

    private WindowManager mWindowManager;
    
    @Override
    public void onCreate() {
        super.onCreate();
        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
  1. 在Service中创建一个浮动窗口,并将其添加到WindowManager中。
public class FloatWindowService extends Service {

    private WindowManager mWindowManager;
    private View mFloatView;

    @Override
    public void onCreate() {
        super.onCreate();
        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        mFloatView = LayoutInflater.from(this).inflate(R.layout.float_window, null);
        WindowManager.LayoutParams params = 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);
        mWindowManager.addView(mFloatView, params);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

在上面的代码中,首先使用LayoutInflater来引入一个布局文件float_window.xml,并将其作为浮动窗口的View。然后创建一个WindowManager.LayoutParams对象,用于设置浮动窗口的一些属性,如宽度、高度、类型、点击事件等。最后将浮动窗口View添加到WindowManager中。

  1. 添加浮动窗口的拖动功能。
public class FloatWindowService extends Service {

    private WindowManager mWindowManager;
    private View mFloatView;
    private float mStartX;
    private float mStartY;
    private float mLastX;
    private float mLastY;

    @Override
    public void onCreate() {
        super.onCreate();
        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        mFloatView = LayoutInflater.from(this).inflate(R.layout.float_window, null);
        WindowManager.LayoutParams params = 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);
        mWindowManager.addView(mFloatView, params);
        mFloatView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        mStartX = event.getX();
                        mStartY = event.getY();
                        mLastX = mStartX;
                        mLastY = mStartY;
                        break;
                    case MotionEvent.ACTION_MOVE:
                        float x = event.getX();
                        float y = event.getY();
                        float deltaX = x - mLastX;
                        float deltaY = y - mLastY;
                        WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) mFloatView.getLayoutParams();
                        layoutParams.x += deltaX;
                        layoutParams.y += deltaY;
                        mWindowManager.updateViewLayout(mFloatView, layoutParams);
                        mLastX = x;
                        mLastY = y;
                        break;
                    case MotionEvent.ACTION_UP:
                        break;
                }
                return false;
            }
        });
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

在上面的代码中,首先声明一些用于记录触摸事件的变量,如起始坐标mStartX和mStartY,上一次坐标mLastX和mLastY。在触摸事件中,首先根据不同的事件类型作出相应的响应,如在ACTION_DOWN事件中记录起始坐标,在ACTION_MOVE事件中处理视图拖动事件等。在拖动事件中,先计算出当前坐标与上一次坐标的增量deltaX和deltaY,然后根据增量修改WindowManager.LayoutParams对象的x和y值,最后使用WindowManager的updateViewLayout方法更新浮动窗口的位置。

注意事项

在创建浮动窗口应用程序时需要注意权限的申请,如SYSTEM_ALERT_WINDOW权限的申请,否则可能会导致应用程序无法正常显示浮动窗口。

参考资料
  1. Android Developers Guide: WindowManager类, https://developer.android.com/reference/android/view/WindowManager

  2. Creating a system overlay window (always on top), https://gist.github.com/lopspower/03fb1cc0ac9f32ef38f4

  3. Android如何实现浮动窗口, http://www.jikexueyuan.com/course/398.html

代码片段见上文。