我有一个使用对话框主题的活动,当有人在此活动窗口之外的任何地方触摸屏幕时,我想关闭(结束)这个活动。我该如何实现?
我有一个使用对话框主题的活动,当有人在此活动窗口之外的任何地方触摸屏幕时,我想关闭(结束)这个活动。我该如何实现?
仅想指出,从一个被主题化为对话框的Activity中获取类似“触摸屏幕外取消”的对话框行为是有方法的,尽管我还没有完全调查它是否具有不良副作用。
在您的Activity的onCreate()方法中,在创建视图之前,您将在窗口上设置两个标志:一个是使其“非模态”,以允许接收事件的视图不仅限于您的Activity的视图。第二个是接收通知其中发生了这些事件之一,这将向您发送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);
}
}
setFinishOnTouchOutside(false);
。 - Mitesh Shah我发现了一个非常简单的答案,对我来说完美地解决了问题。如果你正在使用具有对话框主题的活动,则可以将this.setFinishOnTouchOutside(true);
应用于活动的onCreate()方法。
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_yoptions);
this.setFinishOnTouchOutside(true);
}
非常简单,只需将属性canceledOnTouchOutside = true
设置为真。看这个例子:
Dialog dialog = new Dialog(context)
dialog.setCanceledOnTouchOutside(true);
setFinishOnTouchOutside(true)
,即 this.setFinishOnTouchOutside(true);
。 - Ajay Takur<style name="DialogSlideAnim" parent="@android:style/Theme.Holo.Dialog">
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowCloseOnTouchOutside">true</item>
</style>
然后在您的清单文件中将此主题应用于活动:
<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>
Gregory和Matt的答案结合起来对我最有帮助(适用于Honeycomb和其他版本)。这种方式可以确保当用户尝试触摸取消对话框时,外部视图不会收到触摸事件。
在主Activity中,在onCreate()方法中创建触摸拦截器:
touchInterceptor = new FrameLayout(this);
touchInterceptor.setClickable(true); // otherwise clicks will fall through
if (touchInterceptor.getParent() == null) {
rootViewGroup.addView(touchInterceptor);
}
(rootViewGroup可能必须是FrameLayout或RelativeLayout,LinearLayout可能无法正常工作。)
在onResume()中,将其删除:
rootViewGroup.removeView(touchInterceptor);
接下来,对于对话框主题的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);
}
}
android:theme="@style/Theme.AppCompat.Dialog"
或任何其它对话框主题,API 11及以上版本我们可以使用。if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setFinishOnTouchOutside(false);
}
在活动的onCreate
方法内调用此方法。
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Rect dialogBounds = new Rect();
getWindow().getDecorView().getHitRect(dialogBounds);
if (!dialogBounds.contains((int) ev.getX(), (int) ev.getY())) {
return true;
}
return super.dispatchTouchEvent(ev);
}
我看不懂最佳答案在三星平板3.1版本上的运行情况,因此我做了以下操作:
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
int xmargin = (ViewUtils.getScreenWidth() - Constants.PRODUCT_DIALOG_WIDTH) / 2;
int ymargin = (ViewUtils.getScreenHeight() - Constants.PRODUCT_DIALOG_HEIGHT) / 2;
if (
x < xmargin ||
x > ViewUtils.getScreenWidth() - xmargin ||
y < ymargin ||
y > ViewUtils.getScreenHeight() - ymargin
) {
finish();
return true;
}
return super.onTouchEvent(event);
}
您需要将Constants.PRODUCT_DIALOG_WIDTH和Constants.PRODUCT_DIALOG_HEIGHT替换为您对话框的宽度/高度。我的代码中多次使用,因此我将其定义为常量。
您还需要实现自己的方法来获取屏幕宽度和高度,这在本网站上很容易找到。不要忘记考虑Android标题栏!
虽然代码看起来有些丑陋,但是它可以正常工作。
alert = new AlertDialog.Builder(this)....
alert.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(final DialogInterface arg0) {
Log.i(APP_NAME, "in OnDismissListener");
// removeDialog(R.layout.dialog3);
alert.dismiss();
finish();
}
您可以从Android源代码中引用dialog.java代码:
public boolean onTouchEvent(MotionEvent event) {
if (mCancelable && mCanceledOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN && isOutOfBounds(event)) {
cancel();
return true;
}
return false;
}
private boolean isOutOfBounds(MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
final int slop = ViewConfiguration.get(mContext).getScaledWindowTouchSlop();
final View decorView = getWindow().getDecorView();
return (x < -slop) || (y < -slop) || (x > (decorView.getWidth()+slop)) || (y > (decorView.getHeight()+slop));
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN && isOutOfBounds(event)) {
finish();
return true;
}
return false;
}
private boolean isOutOfBounds(MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
final int slop = ViewConfiguration.get(this).getScaledWindowTouchSlop();
final View decorView = getWindow().getDecorView();
return (x < -slop) || (y < -slop) || (x > (decorView.getWidth() + slop)) || (y > decorView.getHeight() + slop));
}