จะยกเลิกกล่องโต้ตอบโดยคลิกที่ด้านนอกของกล่องโต้ตอบได้อย่างไร


156

ฉันใช้กล่องโต้ตอบที่กำหนดเองสำหรับแอปพลิเคชันของฉัน ฉันต้องการนำไปใช้เมื่อผู้ใช้คลิกที่นอกกล่องโต้ตอบการสนทนาจะถูกยกเลิก ฉันต้องทำอะไรเพื่อสิ่งนี้

คำตอบ:


356

คุณสามารถใช้dialog.setCanceledOnTouchOutside(true);ซึ่งจะปิดกล่องโต้ตอบถ้าคุณสัมผัสนอกกล่องโต้ตอบ

สิ่งที่ต้องการ,

  Dialog dialog = new Dialog(context)
  dialog.setCanceledOnTouchOutside(true);

หรือถ้ากล่องโต้ตอบของคุณอยู่ในรูปแบบที่ไม่ใช่แล้ว

1 - ตั้งค่าสถานะFLAG_NOT_TOUCH_MODALสำหรับแอตทริบิวต์หน้าต่างกล่องโต้ตอบของคุณ

Window window = this.getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);

2 - เพิ่มการตั้งค่าสถานะอื่นไปยังคุณสมบัติของ windows ,, FLAG_WATCH_OUTSIDE_TOUCH- นี้มีไว้สำหรับการโต้ตอบเพื่อรับเหตุการณ์การสัมผัสนอกภูมิภาคที่มองเห็นได้

3 - ลบล้างonTouchEvent()ข้อความโต้ตอบและตรวจสอบประเภทการทำงาน หากประเภทการกระทำคือ ' MotionEvent.ACTION_OUTSIDE' หมายถึงผู้ใช้กำลังโต้ตอบนอกภูมิภาคโต้ตอบ ดังนั้นในกรณีนี้คุณสามารถลดขนาดกล่องโต้ตอบหรือตัดสินใจว่าคุณต้องการทำอะไร ดูพิมพ์ธรรมดา?

public boolean onTouchEvent(MotionEvent event)  
{  

       if(event.getAction() == MotionEvent.ACTION_OUTSIDE){  
        System.out.println("TOuch outside the dialog ******************** ");  
               this.dismiss();  
       }  
       return false;  
}  

สำหรับข้อมูลเพิ่มเติมดูที่วิธียกเลิกข้อความโต้ตอบที่กำหนดเองตามจุดสัมผัส และ วิธีปิดกล่องโต้ตอบที่ไม่ใช่คำกริยาเมื่อแตะที่นอกขอบเขตของกล่องโต้ตอบ


9
วิธีนี้ใช้งานได้ดียกเว้นว่ากิจกรรมที่อยู่ภายใต้ยังตอบสนองต่อกิจกรรมการสัมผัส มีวิธีป้องกันไหม
howettl

ใช่. window.setFlags (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL) ทำให้เกิดปัญหานี้ ฉันโพสต์วิธีแก้ปัญหาด้านล่าง :)
ทราบเรา

เป็นไปได้ไหมที่จะเผยแพร่กิจกรรม 'on-touch-outside' ไปยังกิจกรรมใต้โดยใช้กล่องโต้ตอบที่ไม่ได้กำหนดเองด้วย?
jc

1
@ howettl ฉันได้แก้ไขปัญหาของคุณในโซลูชันของฉันซึ่งฉันได้โพสต์ด้านล่างที่ฉันไม่จำเป็นต้องตั้งค่าสถานะใด ๆ ที่หน้าต่าง
Roman Nazarevych

@MuhammedRefaat - กรุณาดูที่หัวข้อนี้groups.google.com/forum/#!topic/android-developers/VhaiIMl6E_w พวกเขาอธิบายไว้เป็นอย่างดี
user370305

18

เพียงใช้

dialog.setCanceledOnTouchOutside(true);

ฉันรู้ว่านี่เป็นคำตอบที่ถูกต้อง แต่ไม่ได้ผลสำหรับฉันและฉันก็ไม่รู้เหมือนกันว่าทำไม
IgniteCoders

16

คุณสามารถใช้การใช้ onTouchEvent นี้ได้ มันป้องกันจากการตอบสนองภายใต้กิจกรรมกับเหตุการณ์สัมผัส (ดังที่กล่าวถึง Howettl)

@Override
public boolean onTouchEvent ( MotionEvent event ) {
  // I only care if the event is an UP action
  if ( event.getAction () == MotionEvent.ACTION_UP ) {
    // create a rect for storing the window rect
    Rect r = new Rect ( 0, 0, 0, 0 );
    // retrieve the windows rect
    this.getWindow ().getDecorView ().getHitRect ( r );
    // check if the event position is inside the window rect
    boolean intersects = r.contains ( (int) event.getX (), (int) event.getY () );
    // if the event is not inside then we can close the activity
    if ( !intersects ) {
      // close the activity
      this.finish ();
      // notify that we consumed this event
      return true;
    }
  }
  // let the system handle the event
  return super.onTouchEvent ( event );
}

ที่มา: http://blog.twimager.com/2010/08/closing-activity-by-touching-outside.html


9

หรือหากคุณกำลังปรับแต่งกล่องโต้ตอบโดยใช้ธีมที่กำหนดไว้ในสไตล์ xml ของคุณให้วางบรรทัดนี้ในธีมของคุณ:

<item name="android:windowCloseOnTouchOutside">true</item>

สิ่งนี้ใช้ไม่ได้กับ Samsung Galaxy Tab 2 WiFi dialog.setCanceledOnTouchOutside(true);ทำงานได้อย่างยอดเยี่ยม
doplumi

7
dialog.setCanceledOnTouchOutside(true); 

เพื่อปิดกล่องโต้ตอบเมื่อสัมผัสภายนอก

และหากคุณไม่ต้องการปิดการสัมผัสด้านนอกให้ใช้รหัสด้านล่าง:

dialog.setCanceledOnTouchOutside(false);

6

วิธีนี้ควรหลีกเลี่ยงกิจกรรมด้านล่างพื้นที่สีเทาเพื่อดึงกิจกรรมคลิก

ลบบรรทัดนี้ถ้าคุณมี:

window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);

สร้างสิ่งนี้ในกิจกรรมของคุณ

getWindow().setFlags(LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);

จากนั้นแทนที่เหตุการณ์สัมผัสด้วยสิ่งนี้

@Override
public boolean onTouchEvent(MotionEvent ev)
{
    if(MotionEvent.ACTION_DOWN == ev.getAction())
    {
        Rect dialogBounds = new Rect();
        getWindow().getDecorView().getHitRect(dialogBounds);
        if (!dialogBounds.contains((int) ev.getX(), (int) ev.getY())) {
            // You have clicked the grey area
            displayYourDialog();
            return false; // stop activity closing
        }
    }

    // Touch events inside are fine.
    return super.onTouchEvent(ev);
}

4

คุณสามารถลองสิ่งนี้: -

AlterDialog alterdialog;
alertDialog.setCanceledOnTouchOutside(true);

หรือ

alertDialog.setCancelable(true);

และถ้าคุณมีAlterDialog.Builderจากนั้นคุณสามารถลองนี้: -

alertDialogBuilder.setCancelable(true);

4

รหัสนี้ใช้เมื่อใช้คลิกที่กล่องโต้ตอบเวลานั้น hidesoftinput และเมื่อผู้ใช้คลิกด้านนอกของกล่องโต้ตอบเวลานั้นทั้ง softinput และกล่องโต้ตอบอยู่ใกล้

dialog = new Dialog(act) {
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // Tap anywhere to close dialog.
        Rect dialogBounds = new Rect();
        getWindow().getDecorView().getHitRect(dialogBounds);
        if (!dialogBounds.contains((int) event.getX(),
                (int) event.getY())) {
            // You have clicked the grey area
            InputMethodManager inputMethodManager = (InputMethodManager) act
                    .getSystemService(act.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(dialog
                    .getCurrentFocus().getWindowToken(), 0);
            dialog.dismiss();
            // stop activity closing
        } else {
            InputMethodManager inputMethodManager = (InputMethodManager) act
                    .getSystemService(act.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(dialog
                    .getCurrentFocus().getWindowToken(), 0);
        }

        return true;
    }
};

2

วิธีการแก้ปัญหาอื่น ๆ รหัสนี้มาจากแหล่งที่มาของ Android Window คุณควรเพิ่มสองวิธีเหล่านี้ไปยังรหัสแหล่งโต้ตอบของคุณ

@Override
public boolean onTouchEvent(MotionEvent event) {        
    if (isShowing() && (event.getAction() == MotionEvent.ACTION_DOWN
            && isOutOfBounds(getContext(), event) && getWindow().peekDecorView() != null)) {
        hide();
    }
    return false;
}

private boolean isOutOfBounds(Context context, MotionEvent event) {
    final int x = (int) event.getX();
    final int y = (int) event.getY();
    final int slop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
    final View decorView = getWindow().getDecorView();
    return (x < -slop) || (y < -slop)
            || (x > (decorView.getWidth()+slop))
            || (y > (decorView.getHeight()+slop));
}

วิธีนี้ไม่มีปัญหานี้:

วิธีนี้ใช้งานได้ดียกเว้นว่ากิจกรรมที่อยู่ด้านล่างตอบสนองต่อกิจกรรมการสัมผัส มีวิธีป้องกันไหม - howettl


หากคุณไม่ต้องการให้หน้าต่างอื่นรับเหตุการณ์



0

คุณสามารถสร้างbackgroundขนาดหน้าจอทั้งหมดtransparentและฟังonClickเหตุการณ์dismissได้


10
คำตอบที่แย่มาก! แน่นอนว่าสามารถทำได้ แต่โปรดทำอย่างถูกวิธี!
jc

-1

นี่คือรหัส

    dialog.getWindow().getDecorView().setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent ev) {

            if(MotionEvent.ACTION_DOWN == ev.getAction())
            {
                Rect dialogBounds = new Rect();
                dialog. getWindow().getDecorView().getHitRect(dialogBounds);
                if (!dialogBounds.contains((int) ev.getX(), (int) ev.getY())) {
                    // You have clicked the grey area
                    UiUtils.hideKeyboard2(getActivity());
                    return false; // stop activity closing
                }
            }
            getActivity().dispatchTouchEvent(ev);
            return false;
        }
    });

ลองอันนี้ . คุณสามารถซ่อนแป้นพิมพ์เมื่อคุณสัมผัสภายนอก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.