web-dev-qa-db-fra.com

Rejet de la fenêtre popup Android

Une fenêtre contextuelle s'affiche lorsque je clique sur un élément de l'activité de ma liste. Le problème est que la touche back ne la ferme pas. J'ai essayé de saisir la clé de retour dans mon activité de liste, mais cela ne l'a pas enregistrée ... puis j'ai essayé d'enregistrer un onkeylistener dans la vue que je passe à ma fenêtre contextuelle. Comme ça:

pop.setOnKeyListener(new View.OnKeyListener() {

        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            // TODO Auto-generated method stub
            boolean res=false;
            if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
                // do something on back.
                Log.e("keydown","back");
                if (pw.isShowing()) {
                    Log.e("keydown","pw showing");
                    pw.dismiss();
                    res = true;
                }
            } else {
                res = false;
            }
            return res;
        }
    });

qui est passé à un popup comme ceci: 

pw = new PopupWindow(
       pop, 
       240, 
       70, 
       true);

Mais cet auditeur ne tire pas non plus. Pouvez-vous m'aider? Je suis à court d'idées :)

60
Bostjan

En effet, la fenêtre contextuelle ne répond pas aux événements onTouch ou onKey sauf si son arrière-plan est! = Null. Découvrez le code que j'ai écrit pour aider avec cela. Dans le cas de base, vous pouvez appeler PopupWindow#setBackgroundDrawable(new BitmapDrawable()) pour le forcer à agir comme vous le souhaitez. Vous n'aurez pas besoin de votre propre auditeur onKey. Vous devrez peut-être également appeler PopupWindow#setOutsideTouchable(true) si vous souhaitez que le message disparaisse lorsque l'utilisateur clique en dehors des limites de la fenêtre. 

Réponse ésotérique étendue:

La raison pour laquelle l'arrière-plan ne peut pas être null est due à ce qui se passe dans PopupWindow#preparePopup. S'il détecte background != null, il crée une instance de PopupViewContainer et appelle setBackgroundDrawable sur celle-ci et y place votre vue du contenu. PopupViewContainer est fondamentalement une FrameLayout qui écoute les événements tactiles et l'événement KeyEvent.KEYCODE_BACK pour fermer la fenêtre. Si background == null, il ne fait rien de tout cela et utilise simplement votre vue du contenu. Vous pouvez, au lieu de dépendre de PopupWindow pour gérer cela, étendre votre racine ViewGroup pour qu'elle se comporte comme vous le souhaitez.

148
Rich Schuler

Faites comme suit cela fonctionne très bien: 

PopupWindow pw;
LayoutInflater inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.weight_popup, (ViewGroup)findViewById(R.id.linlay_weight_popup));
pw = new PopupWindow(layout,LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT, true);
pw.setBackgroundDrawable(new BitmapDrawable());
pw.setOutsideTouchable(true);
pw.showAsDropDown(btnSelectWeight);
36
Sunil Parmar

Pour les nouveaux projets, il vaut mieux utiliser

popupWindow.setBackgroundDrawable(new ColorDrawable());

au lieu de 

popupWindow.setBackgroundDrawable(new BitmapDrawable());

comme BitmapDrawable est obsolète. Aussi, c'est mieux que ShapeDrawable dans ce cas. J'ai remarqué que lorsque PopupWindow est un rectangle aux coins arrondis, ShapeDrawable remplit les coins en noir.

7
CoolMind

Une solution très simple consiste à écrire pw.setFocusable (true), mais vous ne voulez probablement pas le faire car, dans ce cas, MapActivity ne gérera pas les événements tactiles. 

Une meilleure solution consiste à remplacer la touche Retour, par exemple comme ceci: 

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {

    // Override back button
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        if (pw.isShowing()) {
            pw.dismiss();
            return false;
        }
    }
    return super.onKeyDown(keyCode, event);
} 

Bonne chance!

5
Vanja

Pour les nouveaux chercheurs , la création d'un new BitmapDrawable n'est pas autorisée maintenant (The constructor BitmapDrawable() is deprecated), de sorte que vous devez le changer en new ShapeDrawable() pour que vous changiez:

pw.setBackgroundDrawable(new BitmapDrawable());

À :

pw.setBackgroundDrawable(new ShapeDrawable());

Et tout le travail sera comme:

PopupWindow pw;
LayoutInflater inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.weight_popup, (ViewGroup)findViewById(R.id.linlay_weight_popup));
pw = new PopupWindow(layout,LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT, true);
pw.setOutsideTouchable(true);
pw.setBackgroundDrawable(new ShapeDrawable());
pw.setTouchInterceptor(new OnTouchListener() { // or whatever you want
        @Override
        public boolean onTouch(View v, MotionEvent event)
        {
            if(event.getAction() == MotionEvent.ACTION_OUTSIDE) // here I want to close the pw when clicking outside it but at all this is just an example of how it works and you can implement the onTouch() or the onKey() you want
            {
               pw.dismiss();
               return true;
            }
            return false;
        }

});
pw.showAtLocation(layout, Gravity.CENTER, 0, 0);
4
Muhammed Refaat

juste utiliser ceci 

mPopupWindow.setBackgroundDrawable(new BitmapDrawable(null,""));

qui n'est pas obsolète. J'éviterais la nouvelle forme ShapeDrawable () car son rendu sera lent alors qu'il tente de dessiner une forme lorsque l'écran doit être redessiné. 

4
j2emanue

J'espère que cela vous aidera

 pw.setTouchInterceptor(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // TODO Auto-generated method stub
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                pw.dismiss();
            }
            return true;
        }
    });
3
Dwivedi Ji

vous devez ajouter setBackgroundDrawable(new BitmapDrawable()) pour votre PopupWindow.

1
Carl
pw.setBackgroundDrawable(new ColorDrawable());  

doit l'écrire avant setContentView

Cela fonctionne pour moi.

0
guptaatul91
    private void initPopupWindow() {  
    // TODO Auto-generated method stub  

    View view = getLayoutInflater().inflate(R.layout.main_choice, null);  

    ListView main_menu_listview = (ListView) view.findViewById(R.id.main_menu_listview);  

    ShowMainChoice madapter = new ShowMainChoice(context);
    main_menu_listview.setAdapter(madapter);

    int width = (int)getWindowManager().getDefaultDisplay().getWidth()/2;
    popupWindow = new PopupWindow(view, width,WindowManager.LayoutParams.WRAP_CONTENT);  
    popupWindow.setBackgroundDrawable(new BitmapDrawable());//this is important,如果缺少这句将导致其他任何控件及监听都得不到响应
    popupWindow.setOutsideTouchable(true);
    popupWindow.setFocusable(true);

    main_menu_listview.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {
            // TODO Auto-generated method stub

            Log.e("++++++>", arg2+"");

        }
    });
}

Ce problème est popupwindow! Bonne chance!

0
AlexChu