2011-08-27 11 views
37

Tôi đã tự hỏi liệu có thể nào đó bằng cách nào đó nhấn vào bên ngoài hộp thoại bật lên (hoặc một Hoạt động có chủ đề hội thoại) và loại bỏ nó bằng cách chỉ chạm vào bên ngoài nó?Nhấn vào bên ngoài hộp thoại Android để loại bỏ nó?

tôi đã thực hiện một bức tranh nhanh chóng để minh họa cho nó:

enter image description here

Thông thường, bạn phải nhấn phím lại để bỏ qua hộp thoại, nhưng trên Honeycomb nó có thể là tuyệt vời để có thể lựa chọn chỉ khai thác bên ngoài hộp thoại, do tất cả các màn hình bất động sản.

+1

Tôi cho rằng việc loại bỏ là hành vi mặc định - ít nhất là đối với Hoạt động có chủ đề Dialog. –

Trả lời

47

Ứng dụng của tôi là một hoạt động duy nhất với Theme.Holo.Dialog. Trong trường hợp của tôi câu trả lời khác không hoạt động. Nó chỉ làm cho các ứng dụng nền khác hoặc màn hình khởi chạy để nhận các sự kiện cảm ứng.

Tôi thấy rằng việc sử dụng dispatchTouchEvent hoạt động trong trường hợp của tôi. Tôi nghĩ nó cũng là một giải pháp đơn giản hơn. Dưới đây là một số mẫu mã trên làm thế nào để sử dụng nó để phát hiện vòi bên ngoài hoạt động với một chủ đề Dialog:

@Override 
public boolean dispatchTouchEvent(MotionEvent ev) { 
    Rect dialogBounds = new Rect(); 
    getWindow().getDecorView().getHitRect(dialogBounds); 

    if (!dialogBounds.contains((int) ev.getX(), (int) ev.getY())) { 
     // Tapped outside so we finish the activity 
     this.finish(); 
    } 
    return super.dispatchTouchEvent(ev); 
} 
+12

Điều này hoạt động tốt hơn nếu bạn thay đổi điều kiện if thành 'if (! DialogBounds.contains ((int) event.getX(), (int) event.getY()) && event.getAction() == MotionEvent.ACTION_DOWN)' Bằng cách đó, nó không đóng nếu người dùng vô tình di chuyển ngón tay của họ bên ngoài 'Hoạt động'. – Glitch

+0

Thật tuyệt vời, Glitch - cảm ơn rất nhiều. –

+1

Sử dụng cấp API 8, Sử dụng hoạt động có chủ đề 'android: Theme.Dialog' và với mã này: 'dialogBounds.top' và' dialogBounds.left' có giá trị 0; và 'dialogBounds.bottom' và' dialogBounds.right' có các giá trị của kích thước màn hình, cho thấy cửa sổ diolog thực sự được giả định là toàn màn hình. Vì vậy, tôi không thể đặt mã này để hoạt động. Bất kỳ ý tưởng nào khác tại sao điều này đang xảy ra? – Jorge

14

Có một phương pháp TouchInterceptor mà sẽ gọi khi bạn chạm vào bên ngoài cửa sổ popup

Ví dụ

mWindow.setTouchInterceptor(new OnTouchListener() { 
      @Override 
      public boolean onTouch(View v, MotionEvent event) { 
       if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { 
        mWindow.dismiss(); 

        return true; 
       } 

       return false; 
      } 
     }); 

mWindow là cửa sổ popup

Và nếu bạn muốn cùng một chức năng cho Hoạt động bạn phải làm theo các bước dưới đây.

1) Thêm cờ trước setContentView() phương pháp gọi trong onCreate();

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); 

2) Override onTouchEvent() sự kiện trong Hoạt động

và viết mã dưới đây

@Override 
     public boolean onTouchEvent(MotionEvent event) { 
      if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { 
       Toast.makeText(getApplicationContext(), "Finish", 3000).show(); 
       finish();    
       return true; 
      } 
      return false; 
     } 

Bản sao hoàn chỉnh là ở đây

Hoạt động

package net.londatiga.android; 

import android.app.Activity; 
import android.os.Bundle; 

import android.view.MotionEvent; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.view.View.OnTouchListener; 
import android.view.WindowManager.LayoutParams; 

import android.widget.Button; 
import android.widget.Toast; 

public class NewQuickAction3DActivity extends Activity implements OnTouchListener { 

    @Override 
    public 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); 

     setContentView(R.layout.main); 

    } 


    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { 
      Toast.makeText(getApplicationContext(), "Hi", 3000).show(); 

      return true; 
     } 

     return false; 
    } 
} 

Đây là manifest.xml

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
     package="net.londatiga.android" 
     android:versionCode="1" 
     android:versionName="1.0"> 
    <uses-sdk android:minSdkVersion="7" /> 

    <application android:icon="@drawable/icon" android:label="@string/app_name"> 
     <activity android:name=".NewQuickAction3DActivity" 
        android:label="@string/app_name" android:theme="@android:style/Theme.Holo.Dialog"> 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN" /> 
       <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
     </activity> 

    </application> 
</manifest> 
+2

Chỉ dành cho 'PopupWindow', đúng không? Tôi đang sử dụng một Hoạt động chuẩn với chủ đề Theme.Holo.Dialog trong Honeycomb. –

+0

Tôi đã chỉnh sửa câu trả lời của tôi kiểm tra xem nó – Dharmendra

+0

Vâng, tôi đã thử nó trước khi bạn đã viết nó, nhưng nó đã không hoạt động hoặc :(Thiếu một dấu chấm phẩy trên kết thúc() btw :) –

89
dialog.setCanceledOnTouchOutside(true) 

Sets liệu hộp thoại này bị hủy bỏ khi chạm vào bên ngoài biên giới của cửa sổ.

+2

Đây là giải pháp tốt nhất ... Rất đơn giản. Tại sao đây không phải là câu trả lời? –

+1

Tôi cần nó để làm việc trên một Hoạt động với chủ đề hộp thoại, và điều này sẽ không hoạt động trong trường hợp đó, nhưng tôi đã upvoted nó cho các hộp thoại chung. –

+3

'this.setFinishOnTouchOutside (false);' hoạt động cho một Hoạt động Dialog – Nick

5

Bạn cũng có thể sử dụng Activity#setFinishOnTouchOutside nếu hộp thoại của bạn là Activity. Đó là cách ngắn nhất cho Activity s;)

(Đó là API 11+. Tuy nhiên, API < = 10 thường có kích thước màn hình bình thường.)

+0

Đây là câu trả lời chiến thắng, câu hỏi là giải quyết các Hoạt động theo chủ đề là Hộp thoại, không phải hộp thoại. – JaredBanyard

1

Cũ câu hỏi nhưng chưa một giải pháp:

  1. Cung cấp hoạt động foreground toàn màn hình. Bố cục được sử dụng: Bố cục toàn màn hình phải có nền trong suốt (ví dụ: @null hoặc @android:color/transparent). Bố cục bên trong phải có nền hiển thị.

  2. Thêm OnClickListener vào bố cục bên ngoài vô hình mà finish() thực hiện hoạt động của bạn.

0

Bất kỳ chế độ xem nào trong hộp thoại đều có thể đặt để sử dụng sự kiện chạm để bên dưới không được gọi.

onCreate(){ 
    getWindow().getDecorView().getRootView().setOnTouchListener(new OnTouchListener(){ 
     @Override 
     public boolean onTouch(View v, MotionEvent event) { 
      dialog.dismiss(); 
      return false; 
     } 
    }); 
0
LayoutParams lp=dialogp.getWindow().getAttributes(); 
lp.flags=LayoutParams.FLAG_LAYOUT_NO_LIMITS; 

tôi thêm này và nó hoạt động hoàn hảo trên 3,0 lên, nhưng nên làm việc trên tất cả.

1

Sử dụng kiểu hộp thoại thay vì các kiểu khác.

Ví dụ, sử dụng

public YourCustomDialog(Context context) { 
    super(context, android.R.style.Theme_Holo_dialog_NoActionBar); 
} 

Khi bạn sử dụng phong cách khác như Theme_Translucent_NoTitleBar, hộp thoại sẽ không bị sa thải.

5

Bạn có thể sử dụng

dialog.setCancelable(true\false); 

Đối với vesrions mới nhất của Android;

Nó sẽ vô hiệu hóa sự kiện outSideTouching.

+0

Phiên bản nào? – AbleArcher

+0

Nó được kiểm tra cho tất cả các phiên bản ngoại trừ KITKAT :) – Amt87

3
dialog = new Dialog(MainActivity.this); 
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); 
    dialog.setContentView(R.layout.dialog_layout); 
    dialog.getWindow().setBackgroundDrawableResource(
      android.R.color.transparent); 
    dialog.setCancelable(false); 

    dialog.setCanceledOnTouchOutside(true); 

Kiểm tra xem bạn có dòng mã này hay không ....

dialog.setCanceledOnTouchOutside(true); 
4

Đơn giản chỉ cần tôi viết dialog.setCanceledOnTouchOutside (false); và nó làm việc cho tôi, cửa sổ sẽ không loại bỏ trên vòi nước bên ngoài.

1

this.setFinishOnTouchOutside (sai);

bạn có thể sử dụng