我有一个带有Dialog主题的活动,当有人在此活动窗口外的任何地方触摸屏幕时,我想关闭(完成)此活动?我怎么能这样做?
答案 0 :(得分:96)
只是要指出 是一种从主题为对话框的活动中获得类似对话框的“触摸外部取消”行为的方法,尽管我还没有完全调查它是否有不需要的副作用。
在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);
}
}
答案 1 :(得分:68)
我找到了一个更简单的答案,对我来说非常有效。如果您正在使用具有对话框主题的活动,则可以将this.setFinishOnTouchOutside(true);
应用于活动的onCreate()方法。
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_yoptions);
this.setFinishOnTouchOutside(true);
}
答案 2 :(得分:27)
这很简单,只需设置属性canceledOnTouchOutside = true
即可。看一下这个例子:
Dialog dialog = new Dialog(context)
dialog.setCanceledOnTouchOutside(true);
答案 3 :(得分: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>
然后在您的清单中将此主题应用于活动:
<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>
答案 4 :(得分:8)
Gregory和Matt的答案组合最适合我(对于Honeycomb和大概是其他人)。这样,当用户尝试触摸外部取消对话框时,外部视图将不会获得触摸事件。
在主Activity中,在onCreate()中创建触摸拦截器:
touchInterceptor = new FrameLayout(this);
touchInterceptor.setClickable(true); // otherwise clicks will fall through
在onPause()中添加:
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);
}
}
答案 5 :(得分:6)
如果使用if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setFinishOnTouchOutside(false);
}
之类的对话框主题或任何其他对话框主题。
在API 11上以及之后我们可以使用
onCreate
在活动的{{1}}内调用此内容。
答案 6 :(得分:4)
@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);
}
这段代码解决了我的问题。
答案 7 :(得分:3)
您可以从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));
}
可以解决您的问题。
答案 8 :(得分:3)
我无法在这里得到最佳答案,可以在运行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标题!
这有点难看,我并不自豪,但它有效。
答案 9 :(得分:2)
我让这个工作的唯一方法是
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();
}
即。我必须明确地放弃和完成,否则我最终在屏幕中间有一个小的白色矩形。
答案 10 :(得分:0)
一个Activity有dispatchTouchEvent使用那个
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
finish();
return super.dispatchTouchEvent(ev);
}
答案 11 :(得分:0)
只需将此项添加到styles.xml
:
<style name="alert_dialog" parent="android:Theme.Dialog">
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowBackground">@color/float_transparent</item>
<item name="android:windowAnimationStyle">@null</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:backgroundDimAmount">0.4</item>
</style>
在onCreate()
和setContentView
之前:
setTheme(R.style.alert_dialog);
答案 12 :(得分:0)
使用方法setFinishOnTouchOutside
启用/禁用外部是否可触摸。
这适用于活动。
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_yoptions);
/* your code here */
// set outside touchable
this.setFinishOnTouchOutside(true);
}
答案 13 :(得分:0)
对于那些不想在对话框外部触摸而关闭对话框应用程序的人。 添加此行
this.setFinishOnTouchOutside(false);
它不会关闭对话框
答案 14 :(得分:0)
只需使用此主题。触摸外部后,活动将被取消。
@Override
public Page<PaymentLog> getPaymentLog(int status, Pageable pageable) {
return paymentLogRepository.getAllByStatus(status, pageable);
}
答案 15 :(得分:0)
Kotlin 版本对我有用
alert.setOnDismissListener(DialogInterface.OnDismissListener() {
it.dismiss()
})
答案 16 :(得分:-5)
如果没有API支持,您应该使用FrameLayout填充屏幕,并手动构建弹出窗口。然后,您可以在屏幕上的任何位置接收焦点,并相应地显示/隐藏视图。