android底部上滑锁屏

这篇博客介绍了如何在Android中实现底部悬浮导航栏,并利用AccessibilityService实现上滑锁屏功能。通过设置LayoutParams类型、权限和无障碍服务配置,创建了一个悬浮窗并监听触摸事件来触发锁屏操作。博客还提供了相关代码示例和配置文件的详细说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

各种测试,各种查资料,总算解决了底部上滑锁屏功能的实现。一个底部三大金钢折腾死个人。
最后借助的还是AccessibilityService实现。因为我想实现的底部导航栏一定要显示在屏幕最底端,就算有三大金刚navigationbar,也要置于其顶层。
为了效果显示,我没有设置透明度,正常应用时,我是把背景色取消了

TYPE_ACCESSIBILITY_OVERLAY

TYPE_APPLICATION_OVERLAY

为什么不用 TYPE_APPLICATION_OVERLAY 因为底部导航栏三大金钢挡住无法接收触发事件。
正常的悬浮窗使用这个是完美的,也是官方建议的,但对于有底部导航栏和状态栏这种系统级的window在的时候,没办法,层级不够。
不多说,直接上代码解决方案

AccessibilityService

首先要继承这个类,因为TYPE_ACCESSIBILITY_OVERLAY只能在这个类里面调用,否则就会报错误 Unable to add window – token null is not valid; is your activity running

public class MyAccessibilityService extends AccessibilityService {
    @Override
    public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
    }
        @Override
    public void onInterrupt() {
    }
}

为了实现悬浮窗的绘制,再重载两个方法,开始想放在 oncreate 方法里,出了点小问题,就放在onServiceConnected里了

    @Override
    protected void onServiceConnected() {
        initWindow();
        super.onServiceConnected();
    }

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

具体的窗体加载方法,一些重要关键点在里面加了注释说明

    @SuppressLint("ClickableViewAccessibility")
    private void initWindow() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (Settings.canDrawOverlays(this)) {
                windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
                //region 设置LayoutParams
                WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    layoutParams.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
                } else {
                    layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
                }
                layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                        WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
                        WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS ;
                layoutParams.format = PixelFormat.RGBA_8888; //背景透明效果
                int bottomheight = 20;
                layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
                layoutParams.height = bottomheight;
                layoutParams.gravity = 51; //想要x,y生效,一定要指定Gravity为top和left //Gravity.TOP | Gravity.LEFT
                layoutParams.x = 0; //启动位置
                Point point = new Point();
                windowManager.getDefaultDisplay().getRealSize(point);
                layoutParams.y = point.y - bottomheight;
                //endregion

                //加载悬浮窗布局
                FloatPanelBottomBinding floatView = FloatPanelBottomBinding.inflate(LayoutInflater.from(MyAccessibilityService.this));
                mView = floatView.getRoot();
                //mView.setAlpha((float) 0.1);

                floatView.tvPanel.setOnTouchListener(new View.OnTouchListener() {
                    //记录初使按下时的坐标
                    float startY;

                    @Override
                    public boolean onTouch(View view, MotionEvent motionEvent) {
                        switch (motionEvent.getAction()) {
                            case MotionEvent.ACTION_DOWN:
                                startY = motionEvent.getRawY();
                                break;
                            case MotionEvent.ACTION_UP:
                                float offsetY = motionEvent.getRawY() - startY;
                                if (offsetY < -6) {
                                    //锁屏
                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
                                        performGlobalAction(AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN);
                                }
                                break;
                        }
                        return true;
                    }
                });

                windowManager.addView(mView, layoutParams);
            }
        }
    }

因为我要实现的上滑锁屏,所用我只处理了这一个功能,悬浮窗都出来,如果你想加更多功能还不是想要什么有什么?

AndroidManifest.xml

加服务,加权限,这些和正常的无障碍服务以及悬浮窗相同,本不打算提,怕有的朋友没开发过类似应用,多加个说明吧

加权限

没必要那么多,只要这一个就够了

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

加服务

<!-- 全局返回功能,锁屏功能,开启无障碍服务-->
<service android:name=".services.MyAccessibilityService"
    android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService"/>
    </intent-filter>
    <meta-data android:name="android.accessibilityservice"
        android:resource="@xml/accessibilityservice"/>
</service>

accessibilityservice.xml

res / xml / accessibilityservice.xml
配置文件里面也只加个描述信息就行,多了竟给手机加负担

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/accessibility_desc"/>

Activity

这个主要是检查无障碍服务是否开启,如果没有开启就跳转过去,只能手动开启

//检查是否开启无障碍权限
public static boolean isAccessibilitySettingsOn(Context mContext, MyAccessibilityService accessibilityService) {
    int accessibilityEnabled = 0;
    final String service = mContext.getPackageName() + "/" + accessibilityService.getClass().getCanonicalName();
    try {
        accessibilityEnabled = Settings.Secure.getInt(mContext.getApplicationContext().getContentResolver(),
                Settings.Secure.ACCESSIBILITY_ENABLED);
    } catch (Settings.SettingNotFoundException e) {
        e.printStackTrace();
    }
    TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':');
    if (accessibilityEnabled == 1) {
        String settingValue = Settings.Secure.getString(mContext.getApplicationContext().getContentResolver(),
                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
        if (settingValue != null) {
            mStringColonSplitter.setString(settingValue);
            while (mStringColonSplitter.hasNext()) {
                String accessibility = mStringColonSplitter.next();
                if (accessibility.equalsIgnoreCase(service)) {
                    return true;
                }
            }
        }
    }
    return false;
    //测试时暂不做权限检查
    //return true;
}
//region权限检查
if (!isAccessibilitySettingsOn(this, new MyAccessibilityService())) {
    startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值