2010-06-25 23 views
59

Mam wyświetlone okno wyskakujące po kliknięciu elementu w mojej aktywności na liście. Problem polega na tym, że klawisz Back nie zamyka go. Próbowałem przechwycić klucz z powrotem w mojej aktywności na liście, ale go nie rejestruje ... wtedy próbowałem zarejestrować onkeylistener na widok, który przechodzę do mojego okna wyskakującego. Tak:Okienko wyskakujące z okna wyskakującego z Androidem

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

który jest przekazywany do popup tak:

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

Ale że słuchacz nie ogień ani. Możesz mi pomóc? Nie mam pomysłów :)

+0

Tak, ale okienko zawiera klikalne obrazy ... – Bostjan

Odpowiedz

144

Dzieje się tak dlatego, że okno wyskakujące nie reaguje na zdarzenia onTouch lub onKey, chyba że ma tło, które! = Null. Check out some code I wrote, aby pomóc w tym. W podstawowym przypadku możesz zadzwonić pod numer PopupWindow#setBackgroundDrawable(new BitmapDrawable()), aby zmusić go do działania zgodnie z oczekiwaniami. Nie będziesz potrzebować własnego słuchacza onKey. Możesz również zadzwonić pod numer PopupWindow#setOutsideTouchable(true), jeśli chcesz, aby zniknął, gdy użytkownik kliknie poza granice okna.

Rozszerzony odpowiedź ezoteryczny:

Powodem tło nie może być null jest to, co dzieje się w PopupWindow#preparePopup. Jeśli wykryje background != null, utworzy instancję PopupViewContainer i wywoła na niej setBackgroundDrawable i umieści w niej zawartość. PopupViewContainer to po prostu FrameLayout, który nasłuchuje zdarzeń dotyku i zdarzenia KeyEvent.KEYCODE_BACK, aby zamknąć okno. Jeśli tło == null, nie robi tego i używa tylko widoku treści. Możesz zamiast tego polegać na PopupWindow, aby poradzić sobie z tym, przedłużyć swój root ViewGroup, aby zachowywał się tak, jak chcesz.

+0

mam bardzo podobny problem. Moja CustomView, który jest przekazywany do PopupWindow nie rejestruje onKeyDown() zdarzenia, ale robi zarejestrować onTouchEvent() . – znq

+10

upewnić zadzwonić setBackgroundDrawable przed pokazaniem t on dialogowe ... zajęło mi trochę czasu, aby zrozumieć, że jeden na zewnątrz. – DallinDyer

+2

Mogę zapytać ** ** jak to odkryłeś? Dla mnie to jest po prostu niemożliwe do odgadnięcia, więc albo masz dostęp do jakiejś ukrytej dokumentacji * * lub są czarodziejem :) – Raffaele

5

Naprawdę prostym rozwiązaniem jest napisanie pw.setFocusable (true), ale prawdopodobnie nie chcesz tego robić, ponieważ wtedy MapActivity nie będzie obsługiwać zdarzeń dotykowych.

Lepszym rozwiązaniem jest, aby zastąpić tylną klucza, na przykład tak:

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

powodzenia!

35

Czy według następujących działa dobrze:

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

Mam nadzieję, że to będzie pomoc dla ciebie

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

Witam, czy jest to koniecznością, gdy mamy do czynienia z oknem popup? Lub pw.setOutsideTouchable (true); wystarczy, aby zamknąć okienko wyskakujące po kliknięciu poza oknem podręcznym? – GMsoF

+0

@GMsoF oba muszą, spójrz na moją odpowiedź –

0
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+""); 

     } 
    }); 
} 

Ten problem jest popupwindow decyzja wiadomości bazowych, ponieważ jest blokowanie. Powodzenia

4

Dla nowych poszukiwaczy, jak tworzenie new BitmapDrawable nie wolno teraz (The constructor BitmapDrawable() is deprecated), tak, że trzeba zmienić go na new ShapeDrawable(), tak, że będzie zmienić:

pw.setBackgroundDrawable(new BitmapDrawable()); 

Do:

pw.setBackgroundDrawable(new ShapeDrawable()); 

i cała praca będzie tak:

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

prostu użyć tego

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

który nie jest przestarzała. Chciałbym uniknąć nowego ShapeDrawable() jako jej będzie renderowanie powoli, ponieważ próbuje narysować kształt, gdy potrzebuje ekranu, aby być odświeżana .

6

dla nowych projektów to lepiej użyć

popupWindow.setBackgroundDrawable(new ColorDrawable()); 

zamiast

popupWindow.setBackgroundDrawable(new BitmapDrawable()); 

jak BitmapDrawable jest przestarzała. Ponadto, jest to lepsze niż ShapeDrawable w tym przypadku. Zauważyłem, że kiedy PopupWindow to prostokąt z zaokrąglonymi rogami, ShapeDrawable wypełnia narożniki z czernią.

1

trzeba dodać setBackgroundDrawable(new BitmapDrawable()) na Twój PopupWindow .

Powiązane problemy