如何在窗外触摸时取消以Activity为主题的对话框?

Ale*_*lex 44 android dialog touch android-activity

我有一个带有Dialog主题的活动,当有人在此活动窗口外的任何地方触摸屏幕时,我想关闭(完成)此活动?我怎样才能做到这一点 ?

小智 98

只是想指出,有一种方式来获得对话式"触摸外,取消"从主题的对话的活动的行为,虽然我还没有完全调查它是否有不必要的副作用.

在Activity的onCreate()方法中,在创建视图之前,您将在窗口上设置两个标志:一个用于使其"非模态",以允许除活动视图之外的视图接收事件.第二个是接收其中一个事件发生的通知,它将向您发送ACTION_OUTSDIE移动事件.

如果将活动上的主题设置为对话框主题,您将获得所需的行为.

它看起来像这样:

public class MyActivity extends Activity {

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

    // Make us non-modal, so that others can receive touch events.
    getWindow().setFlags(LayoutParams.FLAG_NOT_TOUCH_MODAL, LayoutParams.FLAG_NOT_TOUCH_MODAL);

    // ...but notify us that it happened.
    getWindow().setFlags(LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);

    // Note that flag changes must happen *before* the content view is set.
    setContentView(R.layout.my_dialog_view);
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    // If we've received a touch notification that the user has touched
    // outside the app, finish the activity.
    if (MotionEvent.ACTION_OUTSIDE == event.getAction()) {
      finish();
      return true;
    }

    // Delegate everything else to Activity.
    return super.onTouchEvent(event);
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 嗨这看起来不错,但是如果我在listview上有活动并且我在视图外部点击,那么即使我返回true,触摸事件也会传递给listview; 知道怎么解决吗? (5认同)
  • @Alex:尝试使用`setFinishOnTouchOutside(false);` (5认同)
  • WindowManager.LayoutParams (3认同)

小智 70

我找到了一个更简单的答案,对我来说非常有效.如果您正在使用具有对话框主题的活动,则可以应用于this.setFinishOnTouchOutside(true);活动的onCreate()方法.

@Override
protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_yoptions);
    this.setFinishOnTouchOutside(true);
}
Run Code Online (Sandbox Code Playgroud)

  • 我正在寻找相反的行为,这个答案也适用于此.我想*不*关闭对话式活动,在这种情况下是一个加载对话框,当用户点击它时.将此设置为(false)有效. (3认同)
  • 这只适用于api 11及以上版本. (2认同)

小智 29

这很简单,只需设置属性即可canceledOnTouchOutside = true.看一下这个例子:

Dialog dialog = new Dialog(context)
dialog.setCanceledOnTouchOutside(true);
Run Code Online (Sandbox Code Playgroud)

  • 这仅适用于*actual*对话框,而不适用于使用对话框主题的常规活动. (5认同)
  • 要使用对话框主题,请在当前对象上调用`setFinishOnTouchOutside(true)`.`this.setFinishOnTouchOutside(真);` (2认同)

ale*_*rik 18

很容易:

首先在style.xml中定义自己的主题:

<style name="DialogSlideAnim" parent="@android:style/Theme.Holo.Dialog">
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowCloseOnTouchOutside">true</item>
</style>
Run Code Online (Sandbox Code Playgroud)

然后在您的清单中将此主题应用于活动:

    <activity
        android:label="@string/app_name"
        android:name=".MiniModeActivity" 
        android:theme="@style/DialogSlideAnim" >
        <intent-filter >
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
Run Code Online (Sandbox Code Playgroud)

  • 该属性仅在api 11之后可用 (4认同)

Ken*_*Ken 8

Gregory和Matt的答案组合对我来说最有效(对于Honeycomb和大概是其他人).这样,当用户尝试触摸外部取消对话框时,外部视图将不会获得触摸事件.

在主Activity中,在onCreate()中创建触摸拦截器:

    touchInterceptor = new FrameLayout(this);
    touchInterceptor.setClickable(true); // otherwise clicks will fall through
Run Code Online (Sandbox Code Playgroud)

在onPause()中添加它:

    if (touchInterceptor.getParent() == null) {
        rootViewGroup.addView(touchInterceptor);
    }
Run Code Online (Sandbox Code Playgroud)

(rootViewGroup可能必须是FrameLayout或RelativeLayout.LinearLayout可能无效.)

在onResume()中,将其删除:

    rootViewGroup.removeView(touchInterceptor);
Run Code Online (Sandbox Code Playgroud)

然后,对于以对话框为主题的Activity,使用Gregory提供的代码(为方便起见,在此处复制):

public class MyActivity extends Activity {   

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

    // Make us non-modal, so that others can receive touch events.   
    getWindow().setFlags(LayoutParams.FLAG_NOT_TOUCH_MODAL, LayoutParams.FLAG_NOT_TOUCH_MODAL);   

    // ...but notify us that it happened.   
    getWindow().setFlags(LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);   

    // Note that flag changes must happen *before* the content view is set.   
    setContentView(R.layout.my_dialog_view);   
  }   

  @Override   
  public boolean onTouchEvent(MotionEvent event) {   
    // If we've received a touch notification that the user has touched   
    // outside the app, finish the activity.   
    if (MotionEvent.ACTION_OUTSIDE == event.getAction()) {   
      finish();   
      return true;   
    }   

    // Delegate everything else to Activity.   
    return super.onTouchEvent(event);   
  }   
}   
Run Code Online (Sandbox Code Playgroud)


har*_*h_v 6

如果使用对话框主题android:theme="@style/Theme.AppCompat.Dialog"或任何其他对话框主题.在API 11和我们可以使用之后

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        setFinishOnTouchOutside(false);
    }
Run Code Online (Sandbox Code Playgroud)

onCreate在活动内部调用此方法.


Mat*_*att -2

如果没有 API 支持,您应该只使用 FrameLayout 来填充屏幕,然后手动构建弹出窗口。然后,您可以在屏幕上的任何位置接收焦点并相应地显示/隐藏视图。

  • 我实际上不同意这个答案得到的许多反对票。它是无 api 支持的唯一合理替代方案。那么,未投票者能否解释一下为什么这是“如此错误”的? (2认同)