您的位置:

Android悬浮窗实现详解

一、Android悬浮窗实现保活的缺点

在Android应用开发中,有时需要使用悬浮窗来实现一些特殊的需求,比如浮层弹窗、置顶通知等。但是悬浮窗会带来一些问题,保活就是其中之一。当我们启动悬浮窗时,系统需要给我们的应用分配系统资源,而此时如果经常操作该悬浮窗,那么系统可能就会kill掉你的应用,导致悬浮窗无法正常显示。当然,我们可以通过设置一些参数来缓解这个问题,比如设置悬浮窗类型、优化代码等。

以下是一个简单的示例代码,用于设置悬浮窗类型为TYPE_SYSTEM_ALERT:

    WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
    layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
    layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
    layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;//设置悬浮窗类型
    layoutParams.format = PixelFormat.RGBA_8888;
    layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
    //创建悬浮窗
    WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
    View view = LayoutInflater.from(this).inflate(R.layout.layout_float_window, null);
    windowManager.addView(view, layoutParams);

二、Android开发悬浮窗

在Android中,悬浮窗的开发需要用到WindowManager类,同时需要注意悬浮窗的权限问题,可以在Manifest.xml中添加如下权限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

为了保证悬浮窗正常显示,需要在代码中动态添加权限:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(context)) {
    //开启悬浮窗设置页面
    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
    context.startActivity(intent);
}

除了上述权限的设置,我们还需要在悬浮窗布局中添加一个关闭按钮,用于在关闭悬浮窗时释放资源。以下代码为一个示例:

//获取关闭按钮
Button btnCloseFloatWindow = (Button) viewFloatWindow.findViewById(R.id.btnCloseFloatWindow);
//添加关闭按钮监听器
btnCloseFloatWindow.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        windowManager.removeView(viewFloatWindow);//移除悬浮窗
    }
});

三、Android悬浮窗实现灵动岛

灵动岛是一个比较流行的悬浮窗应用,它的主要功能是在屏幕上显示一个可供拖拽、伸缩和轮廓调整的悬浮窗,可以通过长按悬浮窗,弹出菜单执行不同的功能。以下是该应用的功能实现简述:

首先,我们需要定义悬浮窗布局,并添加可拖动、伸缩和轮廓调整的属性:

//获取悬浮窗布局
floatingView = LayoutInflater.from(this).inflate(R.layout.layout_floating, null);
//添加可拖动、伸缩和轮廓调整属性
floatLayoutParams = 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 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
        PixelFormat.TRANSLUCENT);

接下来,我们需要监听悬浮窗拖拽事件:

//获取可拖动区域并添加触摸事件监听器
LinearLayout drag = floatingView.findViewById(R.id.dragView);
drag.setOnTouchListener(new View.OnTouchListener() {
    private int x;
    private int y;
    private float screenX;
    private float screenY;
    private float viewX;
    private float viewY;
    private int touchState;

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        boolean moved = false;
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN: //按下事件
                x = floatLayoutParams.x;
                y = floatLayoutParams.y;
                screenX = event.getRawX();
                screenY = event.getRawY();
                viewX = event.getX();
                viewY = event.getY();

                if (touchState == 0) {
                    touchState = 1;
                } else if (touchState == 2) {
                    touchState = 3;
                }
                break;
            case MotionEvent.ACTION_MOVE: //移动事件
                float moveX = event.getRawX() - screenX;
                float moveY = event.getRawY() - screenY;
                if (touchState == 1 && Math.abs(moveX) < 5 && Math.abs(moveY) < 5) {
                    break;
                }

                float moveViewX = event.getX() - viewX;
                float moveViewY = event.getY() - viewY;
                updateViewPosition((int) (x + moveX), (int) (y + moveY));
                updateViewSize((int) moveViewX, (int) moveViewY);
                moved = true;

                if (touchState == 1) {
                    touchState = 2;
                } else if (touchState == 3) {
                    touchState = 4;
                }
                break;
            case MotionEvent.ACTION_UP: //抬起事件
            case MotionEvent.ACTION_CANCEL: //取消事件
                if (!moved && touchState == 1) {
                    Intent intent = new Intent(FloatingService.this, LddWebViewActivity.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
                }

                touchState = 0;
                break;
        }
        return true;
    }
});

最后,我们需要添加弹出菜单的功能:

//获取菜单按钮并添加点击事件监听器
ImageView menu = floatingView.findViewById(R.id.menuView);
menu.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        PopupMenu popupMenu = new PopupMenu(FloatingService.this, view);
        MenuInflater inflater = popupMenu.getMenuInflater();
        inflater.inflate(R.menu.menu_ldd, popupMenu.getMenu());

        popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.sections:
                        Intent intent = new Intent(FloatingService.this, LddSectionsActivity.class);
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        startActivity(intent);
                        break;
                    case R.id.tools:
                        Intent intent2 = new Intent(FloatingService.this, LddToolsActivity.class);
                        intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        startActivity(intent2);
                        break;
                    case R.id.exit:
                        stopSelf();
                        break;
                }
                return true;
            }
        });

        popupMenu.show();
    }
});

四、Android悬浮窗贴边

悬浮窗贴边可以提高应用使用的体验效果,以下代码实现了左、右、上、下四个方向的悬浮窗贴边:

//获取屏幕宽高
DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();
int screenWidth = displayMetrics.widthPixels;
int screenHeight = displayMetrics.heightPixels;

//设置悬浮窗初始位置
floatLayoutParams.x = 0;
floatLayoutParams.y = 0;
windowManager.addView(floatingView, floatLayoutParams);

//获取方向按钮并添加点击事件监听器
ImageView leftView = floatingView.findViewById(R.id.leftView);
leftView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        floatLayoutParams.x = 0;
        windowManager.updateViewLayout(floatingView, floatLayoutParams);
    }
});
ImageView topView = floatingView.findViewById(R.id.topView);
topView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        floatLayoutParams.y = 0;
        windowManager.updateViewLayout(floatingView, floatLayoutParams);
    }
});
ImageView rightView = floatingView.findViewById(R.id.rightView);
rightView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        floatLayoutParams.x = screenWidth - floatingView.getWidth();
        windowManager.updateViewLayout(floatingView, floatLayoutParams);
    }
});
ImageView bottomView = floatingView.findViewById(R.id.bottomView);
bottomView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        floatLayoutParams.y = screenHeight - floatingView.getHeight();
        windowManager.updateViewLayout(floatingView, floatLayoutParams);
    }
});

五、Android Studio悬浮窗

Android Studio是当前使用最广泛的Android应用开发工具,我们可以在它内部实现悬浮窗显示。以下是一个示例代码:

//获取主布局
View content = findViewById(android.R.id.content);

//获取windowManager
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

//创建LayoutParams对象
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;

//获取悬浮窗布局
View floatView = LayoutInflater.from(MainActivity.this).inflate(R.layout.layout_float_window, null);

//添加悬浮窗插入到view中并设置位置
windowManager.addView(floatView, layoutParams);

六、Android悬浮窗源码

以下是Android悬浮窗源码:

public class FloatWindowService extends Service {
    private WindowManager.LayoutParams mParams;
    private WindowManager mWindowManager;
    private View mFloatView;

    @Override
    public void onCreate() {
        super.onCreate();

        //创建一个浮动窗口实例
        mFloatView = LayoutInflater.from(this).inflate(R.layout.float_layout, null);
        mParams = new WindowManager.LayoutParams();
        mParams.type = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY : WindowManager.LayoutParams.TYPE_PHONE;
        mParams.format = PixelFormat.RGBA_8888;
        mParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        mParams.gravity = Gravity.LEFT | Gravity.TOP;
        mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;

        //添加悬浮窗
        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        assert mWindowManager != null;
        mWindowManager.addView(mFloatView, mParams);
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mFloatView != null) {
            mWindowManager.removeView(mFloatView);
        }
    }
}

七、Android应用内悬浮窗

应用内悬浮窗适用于一些特殊的应用场景,例如扫描应用、音乐应用等。以下是一个示例代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private SuspendButtonView suspendButtonView;
    private WindowManager windowManager;
    private WindowManager.LayoutParams layoutParams;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        setUpView();
    }

    private void setUpView() {
        suspendButtonView = new SuspendButtonView(this);
        suspendButtonView.setOnClickListener(this);
        suspendButtonView.setImageResource(R.drawable.ic_launcher);
        layoutParams = new WindowManager.LayoutParams();
        layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION;
        layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        layoutParams.format = PixelFormat.TRANSLUCENT;
        layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
        layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        windowManager.addView(suspendButtonView, layoutParams);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (suspendButtonView != null) {
            windowManager.removeView(suspendButtonView);
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.suspend_button_view:
                break;
        }
    }
}

以上代码定义了一个SuspendButtonView类,它继承自ImageView,并实现了添加到悬浮窗的功能。

Android悬浮窗实现详解

2023-05-19
Android悬浮窗详解

2023-05-20
提高用户体验的Android悬浮窗实现

随着移动互联网的发展,手机成为人们日常生活中必不可少的工具之一。众所周知,应用程序的用户体验是非常重要的,如何让用户更加方便地使用手机应用程序是一个值得探讨的问题。本文主要介绍如何通过Android悬

2023-12-08
如何获取Android悬浮窗权限

一、什么是Android悬浮窗权限? Android悬浮窗权限用于在应用中创建可悬浮于其他应用之上的窗口,让用户可以同时使用其他应用程序。 需要注意的是,自Android 8.0(API级别26)以后

2023-12-08
悬浮窗代码js,windows悬浮窗

本文目录一览: 1、网站悬浮窗代码js控制修改 2、求网站jq右侧客服悬浮窗代码 3、一段悬浮窗的JS代码,在火狐浏览器中没有悬浮效果! 4、JavaScript,点击按钮怎么弹出悬浮窗口啊 5、JS

2023-12-08
打造高效便捷的悬浮窗:实现快捷操作和流畅体验

2023-05-14
增强用户体验:Android悬浮按钮获取快捷操作

2023-05-14
div悬浮在固定位置详解

2023-05-18
js实现浮动窗体实例(网站浮动飘窗js)

本文目录一览: 1、浮动窗口的代码 (html/js) 2、js css 动态悬浮窗 怎么做 3、在网页中插入浮动窗口,js代码或css代码(易看易懂) 4、javascript如何实现弹出浮动窗口

2023-12-08
js实现侧悬浮浮动实例代码(前端 浮动)

本文目录一览: 1、求个左下角JS广告悬浮代码? 2、求一个能用的右侧浮动JS代码 3、JS网页中的浮动窗口代码? 4、浮动窗口的代码 (html/js) 求个左下角JS广告悬浮代码? 漫游于网络之间

2023-12-08
CSS悬浮效果详解

2023-05-17
使用Echarts实现折线图的悬浮竖线显示方法详解

2023-05-17
CSS悬浮详解

2023-05-17
Echarts鼠标悬浮显示数据详解

2023-05-18
包含extjsgrid悬浮框的大小的词条

2022-11-24
java学习笔记(java初学笔记)

2022-11-14
php底部悬浮按钮,php底部悬浮按钮是什么

2022-11-23
印象笔记记录java学习(Java成长笔记)

2022-11-12
发篇java复习笔记(java课程笔记)

2022-11-09
java方法整理笔记(java总结)

2022-11-08