Android 覆盖层可以获取所有触摸并传递它们?

发布于 2025-01-01 07:17:52 字数 1015 浏览 2 评论 0原文

我基本上试图从系统覆盖层之类的东西获取所有触摸事件数据,根据此触摸数据移动我的精灵,然后允许操作系统/主屏幕/浏览器按其应有的方式对数据进行操作(反之亦然)。我发现了类似的问题,但没有什么能引导我去任何我还没有去过的地方:

获取正在接收所有触摸事件的View

(已实现,结果如下) 创建系统覆盖窗口(始终位于顶部)

我能做什么:

我可以抓住所有触摸事件并通过移动我的精灵来对它们采取行动,并且不允许操作系统/主屏幕/浏览器看到其中任何一个,否则我可以允许触摸事件通过,并且只获得“TOUCH_OUTSIDE”供我的应用程序执行。

我未实现的目标:

我一生都无法找到一种方法来让两者都处理数据。我能想到但无法实施的唯一方法是: 拦截我的应用程序中的数据并将其传递到操作系统/主屏幕/浏览器上使用 允许操作系统/主屏幕/浏览器首先获取数据,然后以某种方式获取包含信息的回调 允许操作系统/主屏幕/浏览器获取数据,对数据进行操作,并轮询它们的滚动/位置值,以便在我的应用程序中对其进行操作。

我担心这是不可能的,我想我读过一些我现在找不到的文档中的某个地方: “要么全有要么全无,要么你的视图获取所有事件,要么什么都没有”

(为了避免混淆,我并不是说我有两个视图。我的意思是我有一个视图通过覆盖操作系统/主屏幕的活动/服务控制/浏览器。如果你愿意的话,就像一块玻璃。)

感谢您提供的任何有用的信息,非常感谢!

[更新] 下面发布了我自己关于此事的文档,以免造成混淆。

I'm basically trying to get all touch event data from something like a system overlay, move my sprites around based on this touch data, then allow the OS/homescreen/browser to act upon the data as it should(or vice versa). I have found similar questions, but nothing that leads me anywhere I haven't already been:

Getting the View that is receiving all the touch events

(Implemented, with results below)
Creating a system overlay window (always on top)

What I can do:

I can EITHER grab ALL the touch events and act upon them by moving my sprites and not allow the OS/homescreen/browser to see any of them, OR ELSE I can allow the touch events to pass through and only get a “TOUCH_OUTSIDE” for my app to act upon.

My unattained goal:

I CAN NOT for the life of me figure out a way around getting BOTH to work with the data. The only methods I can think of, that I can't get implemented are:
Intercepting the data in my APP and passing it onto OS/homescreen/browser to work with
Allowing the OS/homescreen/browser to get the data first, and then getting a callback with information somehow
Allowing the OS/homescreen/browser to get the data, act on the data, and the poll them for what their scroll/location values are so as to act upon it in my APP.

I fear that this just isn't possible, I think I read somewhere in some documentation that I can't find now:
“It's all or nothing, either your view gets all the events, or none of them”

(To avoid confusion, I don't mean I have two views. I mean I have one view controlled via activity/service overlaying the OS/homescreen/browser. Like a pane of glass if you will.)

Thank you for any helpful information you can offer, it's very much appreciated!

[UPDATE]
Posted my own documentation on the matter below, so as to not be confusing.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

不交电费瞎发啥光 2025-01-08 07:17:52

发现这个文档几乎说明不可能同时执行这两项操作:
Android:多点触控和 TYPE_SYSTEM_OVERLAY

他们讨论了解决方法,但我没有我认为它们中的任何一个实际上都可以实现我想要做的事情。两者都将事件提供给底层应用程序,并能够窥探它们并为我自己采取行动。

要创建覆盖视图,设置您需要的LayoutParams时
将类型设置为 TYPE_SYSTEM_OVERLAY 并使用该标志
FLAG_WATCH_OUTSIDE_TOUCH。这提出了一个问题,因为随着
Android 文档指出:“您将不会收到完整的
向下/移动/向上手势,仅将第一个向下的位置作为
ACTION_OUTSIDE。”为了接收完整的触摸事件数组
您需要使用 TYPE_SYSTEM_ALERT 类型,但这会导致
覆盖以接管屏幕并停止与其他人的交互
元素。

任何人都想不同意我很想听到好消息:-D

Found this documentation that pretty much states that it's not possible to do both:
Android : Multi touch and TYPE_SYSTEM_OVERLAY

They discuss workarounds but I don't think any of them will actually work for exactly what I'm trying to do. Both given the events to the underlying app, and being able to snoop them to act upon them for myself.

To create an overlay view, when setting up the LayoutParams you need
to set the type to TYPE_SYSTEM_OVERLAY and use the flag
FLAG_WATCH_OUTSIDE_TOUCH. This presents a problem because as the
Android documentation states: "you will not receive the full
down/move/up gesture, only the location of the first down as an
ACTION_OUTSIDE." In order to receive the full array of touch events
you need to use the TYPE_SYSTEM_ALERT type, but this causes the
overlay to take over the screen and stop interaction with other
elements.

Anyone wants to disagree I'd love to hear good news :-D

怕倦 2025-01-08 07:17:52

您可以使用GestureOverlayView,如果您想隐藏它绘制的线条,您可以将颜色设置为透明#00000000,这样它就不会显示出来,然后您就可以捕获所有触摸和手势。

http://developer.android.com/resources/articles/gestures.html

You can use the GestureOverlayView, if you want to hide the lines it draws you can set the color to Transparent #00000000 so it doesn't show up, and then you can capture all touches, and gestures.

http://developer.android.com/resources/articles/gestures.html

万水千山粽是情ミ 2025-01-08 07:17:52

我一直在寻找同样的东西。

这个标志对我

有用 FLAG_NOT_TOUCH_MODAL 适用于 Android 7 和 8 设置,如下所示。

到目前为止,我实现的唯一操作是触摸关闭覆盖窗口。

我还使用了这里的代码 Github 上的示例系统覆盖代码获取事件。

顺便说一句,谷歌地图在 Android 8 上做得非常好。你可以拖动他们的覆盖窗口,调整其大小或关闭它。所有其他应用程序在运行时都可以正常工作。

    var type = 0

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
    {
        type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
    }
    else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
    {
        type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
    }

    var flags = FLAG_NOT_TOUCH_MODAL

    mOverlayLayoutParams = WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, type, flags, PixelFormat.TRANSLUCENT)

I was looking for the same thing.

This flag does the trick for me FLAG_NOT_TOUCH_MODAL

Works on Android 7 and 8 setup as below.

The only action I've implemented so far is a touch to close the overlay window.

I also used code from here Example System Overlay Code on Github which was needed to get the events.

By the way Google Maps does a really nice job with this on Android 8. You can drag their overlay window around, resize it or close it. And all other apps work fine while it's up.

    var type = 0

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
    {
        type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
    }
    else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
    {
        type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
    }

    var flags = FLAG_NOT_TOUCH_MODAL

    mOverlayLayoutParams = WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, type, flags, PixelFormat.TRANSLUCENT)
感性不性感 2025-01-08 07:17:52

这不是最佳解决方案,但它有效。重新启动服务以切换不可触摸的标志。将额外的布尔值添加到 Intent 中
用于启动服务以确定先前的状态切换值。更好的实施方式是激发意图
当窗口正在监听时触摸,并且在一段固定时间后不监听时触摸。

public class bleh extends Service {
    public void onCteqwer(int i) {

        Context context; Class <bleh> context1 = bleh.class;

        WindowManager.LayoutParams params = null;
        WindowManager mang = (WindowManager) getSystemService(WINDOW_SERVICE);

        //check previous state of service
        if(i==0)
            params = new WindowManager.LayoutParams(arg0,arg1,arg2,arg3,arg4,arg5);

        if(i==1)
            params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,arg0,arg1,arg2,arg3,arg4);

        LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
        View mViw = inflater.inflate(arg, null);

        mViw.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return true;
            }
        });

        mang.addView(mViw, params);

        Intent z = new Intent(context, context1);

        if(i==0)
            z.putExtra("name", 1);
        if(i==1)
            z.putExtra("name", 0);

        stopSelf();
        startService(z);
    }

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

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        Bundle i=intent.getExtras();
        int userName = 0;

        if (i != null)
        {
            userName = i.getInt("name");
            onCteqwer(userName);
        }
    }
}

This is not the optimal solution but it works. Restart the service toggling the flag not touchable. put boolean extra to Intent
which is used to startservice to determine previous state toggle value. A better implementation would be to fire the intent on
touch when the window is listening and after a fixed period when not listening.

public class bleh extends Service {
    public void onCteqwer(int i) {

        Context context; Class <bleh> context1 = bleh.class;

        WindowManager.LayoutParams params = null;
        WindowManager mang = (WindowManager) getSystemService(WINDOW_SERVICE);

        //check previous state of service
        if(i==0)
            params = new WindowManager.LayoutParams(arg0,arg1,arg2,arg3,arg4,arg5);

        if(i==1)
            params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,arg0,arg1,arg2,arg3,arg4);

        LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
        View mViw = inflater.inflate(arg, null);

        mViw.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return true;
            }
        });

        mang.addView(mViw, params);

        Intent z = new Intent(context, context1);

        if(i==0)
            z.putExtra("name", 1);
        if(i==1)
            z.putExtra("name", 0);

        stopSelf();
        startService(z);
    }

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

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        Bundle i=intent.getExtras();
        int userName = 0;

        if (i != null)
        {
            userName = i.getInt("name");
            onCteqwer(userName);
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文