WindowManager 不允许通过触摸 [英] WindowManager not allowing to pass touch

查看:154
本文介绍了WindowManager 不允许通过触摸的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 WindowManager 绘制了一个叠加层.它的宽度和高度是 WindowManager.LayoutParams.MATCH_PARENT 透明背景.

I have drawn an overlay using WindowManager. it's width and height are WindowManager.LayoutParams.MATCH_PARENT with transparent background.

我的视图必须匹配父级和处理圆触摸侦听器并将其余触摸传递到下面的屏幕

我在左右角有两个小圆圈.我让它们在屏幕上可拖动,效果很好.但是当我点击可见的主屏幕按钮时.WindowManager 不允许可见项可点击.

I have two small circle in left and right corner. I make them draggable on screen that's working fine. But when I click on visible Home Screen button. WindowManager don't let the visible item clickable.

        int LAYOUT_FLAG = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? WindowManager.
                LayoutParams.TYPE_APPLICATION_OVERLAY : WindowManager.LayoutParams.TYPE_PHONE;

        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.MATCH_PARENT,//changed it to full
                WindowManager.LayoutParams.MATCH_PARENT,
                LAYOUT_FLAG,

                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                |WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                ///| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, this flag can make it in touchable.
                ///WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                PixelFormat.TRANSLUCENT);

        mFloatingView = LayoutInflater.from(this).inflate(R.layout.item_circle_dragging, null);

        mFloatingView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                return false;
            }
        });
        //Add the view to the window
        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        mWindowManager.addView(mFloatingView,params);

item_circle_dragging.xml

<?xml version="1.0" encoding="utf-8"?>
<customviewpracticing.CircleDraggingView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</customviewpracticing.CircleDraggingView>

CircleDragginView onTouchEvent

@Override
public boolean onTouchEvent(MotionEvent event) {

   switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN:
          if(isPointInside(event.getRawX(),event.getRawY()))
            isAllowedToDrag = true;
          Log.d(TAG, "ACTION_DOWN:getRawX= " + event.getRawX() + " getRawY= " + event.getRawY() + " getX= "
                + event.getX() + " getY= " + event.getY());
          break;
        ///return true;
      case MotionEvent.ACTION_MOVE:
          Log.d(TAG, "ACTION_MOVE:getRawX= " + event.getRawX() + " getRawY= " + event.getRawY() + " getX= "
                + event.getX() + " getY= " + event.getY());
          if(isAllowedToDrag){
            center_circle_X = event.getRawX() ;
            center_circle_Y = event.getRawY();
            }/*this.animate().x(event.getRawX()).y(event.getRawY())
                    .setDuration(50).start();*/
          break;
      case MotionEvent.ACTION_UP:
         if(isAllowedToDrag)
            isAllowedToDrag = false;
         break;
      default:
        return true;//I changed it
   }
    // Force a view to draw again
    ///postInvalidate();
    invalidate();
    return true;
}

还尝试在 CircleDraggingViewonTouchEvent 以及主 mFloatingView(根视图)中返回 false.

Also tried returning false in onTouchEvent of CircleDraggingView and also to main mFloatingView (Root View ).

推荐答案

恐怕你不能在同一个视图上这样做,因为触摸事件要么进入你的视图,要么不进入.您是否使用拦截,返回 false 等...它们都取决于事件是否确实到达您的视图,即使如此,返回 false 也不会将事件传递到下面的屏幕,因为它们是不同的过程.在您的情况下,该事件不会到达您的窗口,这意味着您根本无法处理该事件.

You can't do that on the same view I'm afraid, because the touch event either enters to your view, or it does not. Whether you're using intercept, returning false etc... They all depend on whether the event actually reaches your view, and even then, returning false wouldn't pass the event to the below screen, because they are different processes. In your case, the event wouldn't reach your window, and that would mean you can't handle the event at all.

我不完全确定父级做了什么,我相信您在触摸它后尝试通过拖动操作或某种方式将圆形视图移动到此处.因此,我将举例说明如何做到这一点.

I'm not entirely sure what the parent does, I believe you're trying to move the circle view here after touching it, with a drag operation or some sort. So, I'll give an example approach on how you can do it.

可以在您创建的布局参数中指定在左右角添加视图.例如,左上角看起来像这样:

Adding the view in left and right corner can be specified in the layout params you are creating. For instance, top-left would look like this:

params.x = 0;
paramx.y = 0;

右上角看起来像这样:

WindowManager manager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);

Point size = new Point();

// Get the screen dimensions here
manager.getDefaultDisplay().getSize(point);
int screenWidth = point.x;

// Assuming your view has a 40 dp width and height,
// calculate its pixel variant
int circleWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DP, 40, getResources().getDisplayMetrics());

// Target the top-right corner of the screen.
params.x = screenWidth - circleWidth;

// Y coordinate would be 0.
params.y = 0;

视图参数如下所示:

// Assuming your view has a 40 dp width and height,
// calculate its pixel variant
int circleSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DP, 40, getResources().getDisplayMetrics());

WindowManager.LayoutParams params = new WindowManager.LayoutParams(circleSize /* width */, 
circleSize /* height */,
 0 /* x */,
 0 /* y */,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY /* windowType */,
 WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH /* outsideTouch */,
 PixelFormat.TRANSLUCENT /* format */);

之后,移动视图实际上需要更改您的布局参数并更新视图布局.在您的 onTouchEvent 中,您可以执行以下操作:

After that, moving the view would actually require to change your layout params and updating the view layout. In your onTouchEvent you can do something like this:

// Assuming you know the new x and y values of the view, you can
// update the layout params of the view like this:
((WindowManager.LayoutParams) getLayoutParams()).x = targetX;
((WindowManager.LayoutParams) getLayoutParams()).y = targetY;

// To update the view, you need to either call requestLayout() or
// do it from window manager directly.

// If the first way doesn't work, 2nd will work.

// First way:
requestLayout();

// Second way:

// This will get the same window manager the service has.
WindowManager manager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);

// Update the view layout afterwards.
manager.updateViewLayout(this, getLayoutParams());

这样,您可以使用触摸事件移动视图.

That way, you can move the view with the touch event.

需要注意的几点:

  1. 如果你能捕捉到 onTouchEvent 你就知道你已经接触到了圆,所以你不需要使用原始值来执行坐标检查(我指的是 isPointInside() 函数).从所有这些返回 true 将帮助您接收所有事件,但这不是必需的.无论如何,您可能知道生命周期的工作原理.
  2. 每个圆都必须以root身份通过WindowManager.addView()添加到窗口管理器中,这样触摸不会相互干扰,触摸一个圆不在的点会传递事件到下面的屏幕.
  1. If you can capture the onTouchEvent you know that you've touched the circle, so you don't need to perform coordinate checks by using the raw values (I'm referring to isPointInside() function). Returning true from all of them will help you receive all the events, but that's not necessary. You probably know how the lifecycle works anyway.
  2. Each circle must be added to the window manager as root with WindowManager.addView() so that the touches do not interfere each other, and touching a point where circle is not in will pass the event to the below screen.

这将是您的要求的开始,我认为您可以满足您的需求.

This would be a start for your requirement, and I think you can fit this with your needs.

这篇关于WindowManager 不允许通过触摸的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆