Como descartar a caixa de diálogo clicando fora dela?

156

Eu implementei uma caixa de diálogo personalizada para o meu aplicativo. Quero implementar que, quando o usuário clicar fora da caixa de diálogo, a caixa de diálogo será descartada. O que eu tenho que fazer para isso?

Shreyash Mahajan
fonte

Respostas:

356

Você pode usar o dialog.setCanceledOnTouchOutside(true);que fechará a caixa de diálogo se tocar fora dela.

Algo como,

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

Ou, se o seu Diálogo não for modelo,

1 - Defina o sinalizador FLAG_NOT_TOUCH_MODALpara o atributo da janela da sua caixa de diálogo

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

2 - Adicione outro sinalizador às propriedades do Windows ,, FLAG_WATCH_OUTSIDE_TOUCH- este é para o diálogo receber evento de toque fora de sua região visível.

3 - Substitua a onTouchEvent()caixa de diálogo e verifique o tipo de ação. se o tipo de ação for ' MotionEvent.ACTION_OUTSIDE' significa que o usuário está interagindo fora da região da caixa de diálogo. Portanto, nesse caso, você pode alterar o seu diálogo ou decidir o que deseja executar. ver impressão simples?

public boolean onTouchEvent(MotionEvent event)  
{  

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

Para obter mais informações, consulte Como descartar uma caixa de diálogo personalizada com base em pontos de contato? e Como descartar sua caixa de diálogo não modal, quando tocada fora da região da caixa de diálogo

user370305
fonte
9
Isso funciona muito bem, exceto que a atividade abaixo também reage ao evento de toque. Existe alguma maneira de evitar isso?
fácil
Sim. window.setFlags (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); causa esse problema. Eu publiquei uma solução abaixo :)
Unknownweirdo
É possível propagar eventos 'on-touch-outside' para a atividade abaixo usando também uma caixa de diálogo não personalizada?
jc
1
@howettl Resolvi o seu problema na minha solução que publiquei abaixo, onde não preciso definir nenhum sinalizador para a janela.
Roman Nazarevych 07/07
@MuhammedRefaat - Veja este tópico groups.google.com/forum/#!topic/android-developers/VhaiIMl6E_w . Eles descreveram bem.
user370305
18

Basta usar

dialog.setCanceledOnTouchOutside(true);
Ebin Sebastian
fonte
Sei que essa deve ser a resposta certa, mas não funciona para mim e simplesmente não sei por que.
IgniteCoders
16

Você pode usar esta implementação do onTouchEvent. Impede reagir por baixo da atividade ao evento de toque (como mencionado anteriormente).

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

Fonte: http://blog.twimager.com/2010/08/closing-activity-by-touching-outside.html

Lukas Novak
fonte
9

Ou, se você estiver personalizando a caixa de diálogo usando um tema definido em seu estilo xml, coloque esta linha no seu tema:

<item name="android:windowCloseOnTouchOutside">true</item>
Chris.Zou
fonte
Isso não funciona para mim no Samsung Galaxy Tab 2 WiFi. dialog.setCanceledOnTouchOutside(true);funciona maravilhosamente.
Doplumi
7
dialog.setCanceledOnTouchOutside(true); 

para fechar o diálogo ao tocar fora.

E se você não quiser fechar o contato do lado de fora, use o código abaixo:

dialog.setCanceledOnTouchOutside(false);
Naveen
fonte
6

Esse método deve evitar completamente as atividades abaixo da área cinza de recuperação de eventos de clique.

Remova esta linha, se a tiver:

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

Coloque isso em sua atividade criada

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

substitua o evento de toque por este

@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);
}
Desconhecido
fonte
4

Você pode tentar o seguinte: -

AlterDialog alterdialog;
alertDialog.setCanceledOnTouchOutside(true);

ou

alertDialog.setCancelable(true);

E se você tiver um AlterDialog.BuilderEntão você pode tentar o seguinte: -

alertDialogBuilder.setCancelable(true);
Julfikar
fonte
4

Esse código é usado para quando o clique é usado na caixa de diálogo que oculta a entrada e quando o usuário clica no lado externo da caixa de diálogo na hora em que a entrada automática e a caixa de diálogo estão fechadas.

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;
    }
};
Maulik Santoki
fonte
2

Outra solução, esse código foi retirado do código-fonte android de Window Você deve apenas adicionar esses dois métodos ao código-fonte do diálogo.

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

Esta solução não tem este problema:

Isso funciona muito bem, exceto que a atividade abaixo também reage ao evento de toque. Existe alguma maneira de evitar isso? - howettl

Roman Nazarevych
fonte
Você não pode simplesmente fazer seu diálogo tocar modal se você não quiser que outras janelas recebam eventos?
1

Ligue dialog.setCancelable(false);da sua atividade / fragmento.

EKN
fonte
1

A seguir, trabalhou para mim:

myDialog.setCanceledOnTouchOutside(true);
Akanshi Srivastava
fonte
0

Você pode backgroundocupar todo o tamanho da tela transparente ouvir o onClickevento dismiss.

oriolpons
fonte
10
Resposta muito ruim! Claro que isso pode ser feito, mas faça-o da maneira certa!
jc
-1

Aqui está o código

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

Tente este . você pode ocultar o teclado quando tocar fora

Saljith Kj
fonte