Licenciement de la fenêtre pop-up Android

J’ai une fenêtre contextuelle qui s’affiche lorsque je clique sur un élément de mon activité de liste. Le problème est que la clé de retour ne la ferme pas. J’ai essayé d’attraper la clé de retour dans mon activité de liste mais elle ne l’enregistre pas … j’ai alors essayé d’enregistrer un onkeylistener dans la vue que je transmets à 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é à une fenêtre comme celle-ci:

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

Mais cet auditeur ne tire ni l’un ni l’autre. Pouvez-vous m’aider? Je suis à court d’idées 🙂

Cela est dû au fait que la fenêtre contextuelle ne répond pas aux événements onTouch ou onKey, sauf si l’arrière-plan! = Null. Découvrez du code que j’ai écrit pour vous aider. 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 écouteur onKey. Vous devrez peut-être également appeler PopupWindow#setOutsideTouchable(true) si vous souhaitez qu’il 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 nul est à cause de ce qui se passe dans PopupWindow#preparePopup . S’il détecte un background != null il crée une instance de PopupViewContainer et appelle setBackgroundDrawable dessus et y place votre vue de contenu. PopupViewContainer est essentiellement un FrameLayout qui écoute les événements tactiles et l’événement KeyEvent.KEYCODE_BACK pour KeyEvent.KEYCODE_BACK la fenêtre. Si background == null, cela ne fait rien de cela et utilise simplement votre vue de contenu. Vous pouvez, au lieu de dépendre de PopupWindow pour gérer cela, étendre votre ViewGroup racine pour se comporter comme vous le souhaitez.

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

Pour les nouveaux projets, il vaut mieux utiliser

 popupWindow.setBackgroundDrawable(new ColorDrawable()); 

au lieu de

 popupWindow.setBackgroundDrawable(new BitmapDrawable()); 

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

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

Une meilleure solution consiste à remplacer la clé arrière, 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!

Pour les nouveaux chercheurs , la création d’un new BitmapDrawable n’est plus autorisée ( The constructor BitmapDrawable() is deprecated ), de sorte que vous devez le remplacer par un new ShapeDrawable() , de manière à modifier:

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

utilise juste ça

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

qui n’est pas obsolète. Je voudrais éviter que ShapeDrawable () soit rendu lentement car il tente de dessiner une forme lorsque l’écran doit être redessiné.

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

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

  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 luck 的 机制 决定 的 , luck 是 阻塞 式 的 Bonne chance