全屏半透明自定义对话框,忽略触摸并将其分配给底层视图

时间:2014-05-15 09:05:06

标签: android view dialog touch-event

标题可能有点误导,但我不能把我的问题放在一行。

理念

我正在为我的应用程序构建一个屏幕教程,该教程在每个活动的顶部显示一条消息,并附有一些说明。该消息应覆盖ABS和所有内容,它从屏幕顶部占用大约20%。 为了覆盖ABS和其他所有东西,我创建了一个自定义对话框,它具有半透明的背景并横跨整个屏幕。

这是自定义对话框的代码

public class TutorialDialog extends Dialog
{

public TutorialDialog(final Context context)
{   
    super(context);   
}


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);


    this.requestWindowFeature(Window.FEATURE_NO_TITLE);
    // Making dialog content transparent.
    this.getWindow().setBackgroundDrawable(
            new ColorDrawable(Color.TRANSPARENT));
    // Removing window dim normally visible when dialog are shown.
    this.getWindow().clearFlags(
            WindowManager.LayoutParams.FLAG_DIM_BEHIND);


    // Setting position of content, relative to window.
    WindowManager.LayoutParams params = this.getWindow().getAttributes();
    params.gravity = Gravity.TOP | Gravity.LEFT;
    params.x = 100;
    params.y = 20;
    // If user taps anywhere on the screen, dialog will be cancelled.
    this.setCancelable(false);

    this.setContentView(R.layout.tutorial_overlay_dialog);  





}

Dialog的XML文件非常简单,带有文本框和关闭按钮:

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

<TextView
    android:id="@+id/txtHint"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:background="@android:color/darker_gray"
    android:padding="3dp"
    android:text="Explain what to do here"
    android:textColor="@android:color/white" />

  <Button
    android:id="@+id/btnTutorialClose"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_alignParentRight="true"
    android:text="Close" />

</RelativeLayout>

问题

我希望自定义对话框忽略触摸事件并将它们转发到对话框后面的视图。我可以通过在创建Dialog

中添加此行来实现此目的
getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);

但是,此行将转发所有触摸事件,并且我希望在对话框中有一个关闭按钮以关闭教程。

TL; DR版

我想拦截我的Dialog中的所有触摸事件,除了我的&#34;关闭&#34;按钮,并将所有其余部分转发到底层视图。

如果我的问题听起来有点复杂,请问我,我会更详细地解释任何部分。 非常感谢你!

更新

According to this SO question,如果我在自定义对话框中覆盖onTouchEvent方法并为所有触摸事件返回false,则它们将由&#34; Children视图&#34;处理。 我尝试了它并没有起作用,因为我认为底层视图不完全是儿童观点,是吗?

2 个答案:

答案 0 :(得分:2)

由于不同的人的帮助,我想出了如何解决这个问题。

为了拦截所有触摸事件,处理它们(确定触摸事件发生的位置)然后将它们传递给底层Activity,我不得不重写dispatchTouchEvent

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
    case MotionEvent.ACTION_UP: {
        if (isClose) {
            // Tests if the touch event was inside the Close button boundries
            if (Utils.inViewBounds(btnClose, (int) ev.getRawX(),(int) ev.getRawY())) {
                this.dismiss();
                return true;
            }

        }

        else {
            isClose = false;
            callingActivity.dispatchTouchEvent(ev);
        }

        return false;
    }
    case MotionEvent.ACTION_DOWN: {
        if (Utils.inViewBounds(btnClose, (int) ev.getRawX(),
                (int) ev.getRawY())) {
            isClose = true;
            return true;
        }

        else {
            callingActivity.dispatchTouchEvent(ev);
        }

        return false;

    }

    }

    callingActivity.dispatchTouchEvent(ev);
    return false;
}

本节中的重要代码是callingActivity.dispatchTouchEvent(ev)此代码会将触摸事件传播到启动对话框的Activity。然后,Activity可以正常方式处理触摸事件。

答案 1 :(得分:1)

由于您使用了标志FLAG_NOT_TOUCHABLE,所有事件都会被传递,因此您无法真正控制哪个视图应该拦截它,因为该标志在整个窗口的上下文中工作。

但是,有一项工作

  1. 使用按钮大小获取屏幕上按钮的坐标,以在屏幕上显示矩形区域。
  2. 现在添加Touch listenerGesture listener并在屏幕上获取触摸事件的位置,如果触摸事件位于您之前映射按钮的矩形区域内,则调用按钮单击以编程方式监听这个btnTutorialClose.performClick();
  3. 修改

    1&GT;尝试扩展任何布局并覆盖onInterceptTouchEvent以查看是否有任何事件

    2 - ;在这样的onCreateView上附加一个监听器

    Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_slide, container, false);
        LinearLayout layout = (LinearLayout)rootView.findViewById(R.id.layout)// get your root  layout
        layout.setOnTouchListener(new OnTouchListener() {
    
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return false;
            }
        });
    return rootView;
    }