Android中悬浮窗的实现

最近项目里面有使用悬浮签名功能,在github上找了几个项目学了一下,自己并记录一下。

因为目前 我只需要 悬浮 和 手写 两个功能所以我就简单的实现了一下自己的代码:Github

这篇文章只记录悬浮的实现

悬浮权限:

需要添加权限:

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

权限检查:

private void checkSetting() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!Settings.canDrawOverlays(this)) {
                Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT).show();
                startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), REQUEST_CODE);
            } else {
                show();
            }
        } else {
            show();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_CODE) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (!Settings.canDrawOverlays(this)) {
                    Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();
                } else {
                    show();
                }
            }
        }
    }

悬浮的实现:

需要获取WindowManager,然后创建自己显示的View,并为View设置LayoutParams,这个过程同其他的ViewGroup是一致的(都实现了ViewManager)

最后 使用  addView(View view, ViewGroup.LayoutParams params) 添加到窗口上

这个类是对悬浮窗的定义,包含view 和 布局参数 的生成:     

/**
 * @program: DoodleView
 * @description: Describe the floating view and control how it is displayed
 * @author: lee
 * @create: 2020-12-21 15:00
 */
public interface ISuspension {

    WindowManager.LayoutParams getLayoutParams();

    View createView();
}
    WindowManager windowManager;
    View showingView;

    private void create() {
        // 新建悬浮窗控件
        showingView = suspension.createView();
        WindowManager.LayoutParams layoutParams = suspension.getLayoutParams();
        // 将悬浮窗控件添加到WindowManager
        getWindowManager().addView(showingView, layoutParams);
    }

这里的view就是普通的View即可

ViewGroup.LayoutParams 需要注意的就比较多了,也是悬浮实现的重要类:

1.属性的设置

    @Override
    public WindowManager.LayoutParams getLayoutParams() {
        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //layoutParams.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            //app 内有效
            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION;
        }
        //整个 系统有效(慎用)
//layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;

        //设置没有焦点不能touch,这样其他的界面才可以滑动和操作
        //如果想独占触摸事件就关闭这句话
//      layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
//                            | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;

        layoutParams.format = PixelFormat.RGBA_8888;

        //获取屏幕大小
        Display display = getWindowManager().getDefaultDisplay();
        Point outSize = new Point();
        display.getSize(outSize);
        int width = outSize.x;
        int height = outSize.y;

        //根据需要设置位置大小
        layoutParams.width = width;
        layoutParams.height = height / 2;
        layoutParams.x = 0;
        layoutParams.y = height / 2;
        return layoutParams;
    }

2.大小位置的设置

    //获取屏幕大小
    Display display = getWindowManager().getDefaultDisplay();
    Point outSize = new Point();
    display.getSize(outSize);
    int width = outSize.x;
    int height = outSize.y;
                    
    //根据需要设置位置大小
    layoutParams.width = width;
    layoutParams.height = height / 2;
    layoutParams.x = 0;
    layoutParams.y = height / 2;

现在简单的悬浮就可以实现了,至于 状态改变(平移,变大小,变透明,动画效果),我后面有用到我再来记录!!!

加餐

从这个结构我们可以看出来所有属性中的重点中的重点就是这这定义了>。<

他们分别对应属性:type(窗口类型),flags(各种行为选项/标志),softInputMode(任何软输入区域所需的操作模式),layoutInDisplayCutoutMode(如果存在,控制窗口的布局方式DisplayCutout)。

type  -  在API级别1中添加

窗口的常规类型。窗口类型主要分为三类:

常用值:

TYPE_ACCESSIBILITY_OVERLAY:被连接覆盖的窗口,用于拦截用户交互,而不会更改可访问性服务可以自检的窗口。特别是,可访问性服务只能自检可见用户可以与之交互的窗口,他们可以触摸这些窗口或可以键入这些窗口。例如,如果有一个可触摸的全屏可访问性覆盖,则可访问性服务将自检其下方的窗口,即使它们被可触摸窗口覆盖。

TYPE_APPLICATION:(Activity内有效)普通应用程序窗口。的token必须是令牌识别窗口属于谁的活动。在多用户系统中,仅在拥有用户的窗口上显示。

TYPE_APPLICATION_ATTACHED_DIALOG:类似TYPE_APPLICATION_PANEL,但是窗口的布局与顶级窗口的布局相同,而不是其容器的子级。

TYPE_APPLICATION_MEDIA:用于显示媒体(例如视频)的窗口。这些窗口显示在其附加窗口的后面。

TYPE_APPLICATION_OVERLAY: (APP内有效)应用程序覆盖窗口显示在所有活动窗口上方(介于FIRST_APPLICATION_WINDOW和之间的类型LAST_APPLICATION_WINDOW),但显示在关键系统窗口(例如状态栏或IME)下方。系统可以随时更改这些窗口的位置,大小或可见性,以减少用户的视觉混乱并管理资源。需要android.Manifest.permission#SYSTEM_ALERT_WINDOW许可。系统将使用这种窗口类型调整进程的重要性,以减少低内存杀手杀死进程的机会。在多用户系统中,仅在拥有用户的屏幕上显示。

TYPE_PHONE(慎用):(整个系统有效)窗口类型:电话。这些是非应用程序窗口,提供用户与电话的交互(尤其是来电)。这些窗口通常位于所有应用程序的上方,但位于状态栏的后面。在多用户系统中,在所有用户的窗口上显示。

TYPE_SYSTEM_ALERT(慎用):窗口类型:系统窗口,例如低电量警报。这些窗口始终位于应用程序窗口的顶部。在多用户系统中,仅在拥有用户的窗口上显示。

-------有状态的

TYPE_STATUS_BAR:窗口类型:状态栏。只能有一个状态栏窗口。它位于屏幕顶部,所有其他窗口都向下移,使其位于屏幕下方。在多用户系统中,在所有用户的窗口上显示。

TYPE_INPUT_METHOD:窗口类型:内部输入法窗口,显示在普通UI上方。可以调整应用程序窗口的大小或平移该窗口,以保持输入焦点在显示此窗口时可见。在多用户系统中,仅在拥有用户的窗口上显示。

 


flags    -   Added in API level 1 

Various behavioral options/flags. Default is none.

See Also

softInputMode  - 在API级别3中添加

 

任何软输入区域所需的操作模式。可以是以下各项的任意组合:

可以通过android.R.attr#windowSoftInputMode属性在主题中控制此标志。

layoutInDisplayCutoutMode  -  在API级别28中添加

 

如果存在,控制窗口的布局方式DisplayCutout

默认为LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
值可以是0或的组合android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULTandroid.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGESandroid.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER,和android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值