Dialogテーマのアクティビティがあり、誰かがこのアクティビティのウィンドウの外のどこかで画面に触れたら、このアクティビティを閉じます(終了します)?これどうやってするの ?
isダイアログをテーマにしたアクティビティからダイアログのような「タッチしてキャンセルする」動作を取得する方法を指摘するだけですが、望ましくない副作用があるかどうかは完全には調査していません。
アクティビティのonCreate()メソッド内で、ビューを作成する前に、ウィンドウに2つのフラグを設定します。1つは「非モーダル」にし、アクティビティのビュー以外のビューがイベントを受信できるようにします。 2番目は、それらのイベントの1つが発生したという通知を受信することです。これにより、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);
}
}
さらに簡単な答えが見つかりました。ダイアログテーマでアクティビティを使用している場合は、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);
非常に簡単に可能です:
まず、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>
グレゴリーとマットの回答の組み合わせは、私にとって(ハニカムおよびおそらく他の人にとって)最適に機能しました。この方法では、ユーザーがダイアログの外側をタッチしてキャンセルしようとしたときに、外側のビューはタッチイベントを取得しません。
メインアクティビティで、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);
次に、ダイアログをテーマにしたアクティビティのために、提供されたコード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);
}
このコードは私の問題を解決します。
Dialog.Javaコードは、Android source:
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));
}
あなたの問題を解決できます。
ここでは、3.1を実行しているSamsungタブで作業するためのトップアンサーを取得できなかったため、次のようにしました。
@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();
}
つまり、明示的に終了と終了の両方を入力する必要がありました。そうしないと、画面の中央に小さな白い長方形ができてしまいました。
タッチがダイアログの外にある場合、ダイアログアプリケーションを閉じたくない場合。この行を追加
this.setFinishOnTouchOutside(false);
ダイアログボックスは閉じません。
この項目を_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);
_
アクティビティはdispatchTouchEventにそれを使用させます
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
finish();
return super.dispatchTouchEvent(ev);
}
メソッドsetFinishOnTouchOutside
を使用して、外部がタッチ可能かどうかを有効/無効にします。
これは活動のために働いています。
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_yoptions);
/* your code here */
// set outside touchable
this.setFinishOnTouchOutside(true);
}