文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android WindowManger实现桌面悬浮窗功能

2023-05-18 08:36

关注

如果想实现一个在桌面显示的悬浮窗,用DialogPopupWindowToast等已经不能实现了,他们基本都是在Activity之上显示的,如果想实现在桌面显示的悬浮窗效果,需要用到WindowManager来实现了。

效果图

使用WindowManager实现

        sys_view = new SmallWindowView(mContext);
        sys_view.setText("50%");
        sys_view.setOnTouchListener(this);
        windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        int screenWidth = 0, screenHeight = 0;
        if (windowManager != null) {
            //获取屏幕的宽和高
            Point point = new Point();
            windowManager.getDefaultDisplay().getSize(point);
            screenWidth = point.x;
            screenHeight = point.y;
            layoutParams = new WindowManager.LayoutParams();
//            layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
//            layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
            layoutParams.width = 200;
            layoutParams.height = 200;
            //设置type
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                //26及以上必须使用TYPE_APPLICATION_OVERLAY   @deprecated TYPE_PHONE
                layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
            } else {
                layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
            }
            //设置flags
            layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
            layoutParams.gravity = Gravity.START | Gravity.TOP;
            //背景设置成透明
            layoutParams.format = PixelFormat.TRANSPARENT;
            layoutParams.x = screenWidth;
            layoutParams.y = screenHeight / 2;
            //将View添加到屏幕上
            windowManager.addView(sys_view, layoutParams);
        }
windowManager.updateViewLayout(sys_view, layoutParams);
windowManager.removeView(sys_view);

通过上面的代码就可以实现一个桌面悬浮窗功能了。

注意:在6.0以上,需要在Manifest.xml中声明 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />权限并且在开启悬浮窗时动态判断权限,如果没有此权限需要跳到设置页面去设置,看下官方文档的说明:

SYSTEM_ALERT_WINDOW

分析

1、添加悬浮窗: 通过Context.getSystemService(Context.WINDOW_SERVICE)获得一个WindowManager(以下简称VM), VM是外界访问Window的入口,ActivityDialogToast等其视图都是依附在Window之上的,WindowView的直接管理者,VM继承自ViewManager,其添加、刷新、删除方法也是来自ViewManager:

public interface ViewManager
{   public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

VM有一个静态内部类WindowManager.LayoutParamsWindow的各个属性在这个内部类中设置:

2、更新悬浮窗位置: 在ViewOnTouchEvent中或OnTouch中更新layoutParams.xlayoutParams.y的值并通过windowManager.updateViewLayout()重新设置悬浮窗Window在屏幕中的位置,如下:

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int mInScreenX = (int) event.getRawX();
        int mInScreenY = (int) event.getRawY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastX = (int) event.getRawX();
                mLastY = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                layoutParams.x += mInScreenX - mLastX;
                layoutParams.y += mInScreenY - mLastY;
                mLastX = mInScreenX;
                mLastY = mInScreenY;
                windowManager.updateViewLayout(sys_view, layoutParams);
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return true;
    }

3、删除悬浮窗: 删除比较简单,直接调用windowManager.removeView(view)viewWindow中删除即可。

问题

6.0以上使用时,需要动态申请该悬浮窗权限,如下:

//判断有没有悬浮窗权限,没有去申请
if(!Settings.canDrawOverlays(context)){
     Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                Uri.parse("package:" + context.getPackageName()));
     context.startActivityForResult(intent, REQUEST_CODE);
}
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case REQUEST_CODE:
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return;
                if (!WindowUtil.canOverDraw(this)) {
                    toast("悬浮窗权限未开启,请在设置中手动打开");
                    return;
                }
                WindowController.getInstance().showThumbWindow();
                break;
        }
    }

通过Settings.canDrawOverlays(context)判断是否有悬浮窗权限,如果没有,跳转到设置页面去设置,并在onActivityResult ()中得到申请结果,看似很完美,但在实际测试中,发现在8.0以上的手机上有问题,即使在设置中同意了权限,8.0的手机Settings.canDrawOverlays(context)总是返回false,不过在关闭页面重新调用此方法时,又返回的true,感觉是有一定的延迟,google了一下,发现别人同样遇到了这个问题,貌似已经给google提交了bug单,可以看此博客: http://paskov.vmsoft-bg.com/settings-candrawoverlays-allays-returns-false-on-android-o/ ,不过博客中的解决方法用我的8.0手机(HUAWEI MATE10)依然不起作用,暂时还没深入研究,有解决此问题的还希望不吝赐教。

以上例子的源码地址:https://github.com/crazyqiang

参考

【1】developer.android.com/reference/a…

到此这篇关于Android WindowManger实现桌面悬浮窗功能的文章就介绍到这了,更多相关Android桌面悬浮窗内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯