У меня есть активность с темой Dialog, и я хотел бы закрыть (закончить) эту активность, когда кто-то коснется экрана где-нибудь за пределами этого окна активности? Как я могу это сделать?
Как отменить диалог, например "Активность", когда он коснулся за пределами окна?
Ответ 1
Если поддержка API отсутствует, вы должны просто использовать FrameLayout для заполнения экрана и вручную создать всплывающее окно. Затем вы можете получать фокус в любом месте экрана и соответственно отображать/скрывать.
Ответ 2
Просто укажем, что есть способ получить диалоговое поведение "touch out to cancel" из Activity themed в качестве диалога, хотя я не полностью изучил, имеет ли он нежелательные побочные эффекты.
Внутри вашего действия onCreate(), перед созданием представления, вы должны установить два флажка в окне: один, чтобы сделать его "немодальным", чтобы разрешить представлениям, отличным от ваших видов активности, получать события. Во-вторых, необходимо получить уведомление о том, что произошло одно из этих событий, которое отправит вам событие ACTION_OUTSDIE move.
Если вы установите тему в действии на тему диалога, вы получите нужное поведение.
Это выглядит примерно так:
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);
}
}
Ответ 3
Я нашел еще более простой ответ, который отлично сработал у меня. Если вы используете действие с темой диалога, вы можете применить this.setFinishOnTouchOutside(true);
к методу onCreate().
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_yoptions);
this.setFinishOnTouchOutside(true);
}
Ответ 4
Это очень просто, просто установите свойство canceledOnTouchOutside = true
. посмотрите на пример:
Dialog dialog = new Dialog(context)
dialog.setCanceledOnTouchOutside(true);
Ответ 5
Это возможно довольно легко:
Сначала определите свою собственную тему в 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>
Ответ 6
Комбинация ответов Григория и Мэтта работала лучше всего для меня (для сотовых и, предположительно, для других). Таким образом, просмотр снаружи не будет получать события касания, когда пользователь попытается коснуться-вне-отменить диалог.
В основной операции создайте сенсорный перехватчик в 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);
}
}
Ответ 7
Если вы используете диалоговую тему типа android:theme="@style/Theme.AppCompat.Dialog"
или любую другую тему диалога.
В API 11 и после того, как мы сможем использовать
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setFinishOnTouchOutside(false);
}
вызовите это внутри onCreate
активности.
Ответ 8
@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);
}
Этот код решает мою проблему.
Ответ 9
Я не мог получить главный ответ здесь, чтобы работать на вкладке Samsung с 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 в этом!
Это отвратительно, и я не горжусь, но он работает.
Ответ 10
Вы можете ссылаться на код dialog.java из источника android:
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));
}
может решить вашу проблему.
Ответ 11
Единственный способ, которым я работал, это
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();
}
то есть. Я должен был убрать и уволить, и закончить в явном виде, иначе у меня появился маленький белый прямоугольник в середине экрана.
Ответ 12
В Activity есть функция dispatchTouchEvent, которая
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
finish();
return super.dispatchTouchEvent(ev);
}
Ответ 13
Просто добавьте этот элемент в 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);