2012-05-02 12 views
10

Chciałbym użyć PopupWindow z następujących zachowań/funkcje:Unikanie PopupWindow zwolnienie po dotknięciu poza

  • Jest aktywowana (zawiera interaktywne kontroli wewnątrz np przyciski.)
  • The View „pod” popupwindow ma konsumować akcenty poza popup prawidłowo
  • .. ale popupwindow musi pozostać na ekranie nawet po kliknięciu poza

Znalazłem kilka postów dotyczących PopupWindo w, ale żaden z nich nie zadał pytanie, jak radzić sobie z taką sytuacją ..

Myślę, że wypróbowałem każdą możliwą kombinację setOutsideTouchable(), setFocusable(), setTouchable(), ale utknąłem. Popup zajmuje się kliknięciami poprawnie, ale jest odrzucany zawsze, gdy dotyka na zewnątrz.

Mój obecny kod jest:

View.OnTouchListener customPopUpTouchListenr = new View.OnTouchListener(){ 

    @Override 
    public boolean onTouch(View arg0, MotionEvent arg1) { 
     Log.d("POPUP", "Touch false"); 
     return false; 
    } 

}; 


LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
LinearLayout layout= (LinearLayout)inflater.inflate(R.layout.insert_point_dialog, null); 
PopupWindow pw = new PopupWindow(layout,400,200,true); 
pw.setOutsideTouchable(true); 
pw.setTouchable(true); 
pw.setBackgroundDrawable(new BitmapDrawable()); 
pw.setTouchInterceptor(customPopUpTouchListenr); 
pw.showAtLocation(frameLayout, Gravity.BOTTOM, 0, 0); 

Moja Ogólnym celem jest stworzenie pływające okno, które zachowuje się jak „palety narzędzi” w oprogramowanie, takie jak GIMP: ma wewnątrz kilka kontrolek, na wierzchu aż zamknięty Przycisk "X" i pozwalający na interakcję z kontrolkami na zewnątrz - pod nim .. Może jest jakiś lepszy sposób na zrobienie tego, a nie PopupWindow? Ale nadal nie znalazłem odpowiedniej kontroli.

Odpowiedz

2

pw.setOutsideTouchable (fałsz);

+2

Nie działa to samo (popup znika po kliknięciu na zewnątrz, wejście do onTouch). Jak podano tutaj: [link] (http://stackoverflow.com/questions/7271784/open-a-popupwindow-and-let-the-outsides-still-touchable) aktywowane wyskakujące okienka ignorują ustawienie setOutsideTouchable. –

6

Wystarczy usunąć pw.setBackgroundDrawable(new BitmapDrawable());

2

Spróbuj pw.setBackgroundDrawable (null);

7

to zbyt późno, ale dla ludzi, którzy Ta rzeczy wystarczy zmienić kolejność wierszy

pw.showAtLocation(frameLayout, Gravity.BOTTOM, 0, 0); 
pw.setOutsideTouchable(true); 
pw.setTouchable(true); 
pw.setBackgroundDrawable(new BitmapDrawable()); 
pw.setTouchInterceptor(customPopUpTouchListenr); 

zamiast

pw.setOutsideTouchable(true); 
pw.setTouchable(true); 
pw.setBackgroundDrawable(new BitmapDrawable()); 
pw.setTouchInterceptor(customPopUpTouchListenr); 
pw.showAtLocation(frameLayout, Gravity.BOTTOM, 0, 0); 

umieszczenie czegokolwiek po metody showatlocation sprawia, że ​​jak nic nie ma

+0

Nie działa .... działa nawet po ponownym ustawieniu dla mnie .. – charlie

0

możliwe jest ustawienie opcji Focus (false) dla PopupWindow

przyciski nadal być klikalny, ale bez zachowania kliknięcie wizualnej (niektóre niestandardowe obsługi zmusić pokazu kliknięcie?)

Poniżej przykładowy pływające okno z „zawsze na wierzchu” opcji

oryginalnym układzie obok okna pływający jest w pełni funkcjonować w obu przypadkach, ponadto możliwe jest zastosowanie okien dialogowych i innych wyskakujące okienka, gdy okno jest nadal pływające

również okno jest wielokrotnego użytku

final static int buttonAlpha = 0xDF; 
final static float buttonTextSize = 12f; 

public final void addPopupButton(LinearLayout linearLayout, String title, android.view.View.OnClickListener onClickListener) 
{ 
    Button button = new Button(this.getContext()); 
    button.setText(title); 
    button.setTextSize(buttonTextSize); 
    button.getBackground().setAlpha(buttonAlpha); 
    button.setOnClickListener(onClickListener); 
    linearLayout.addView(button, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); 
} 

public final Button addPopupCheckbox(LinearLayout linearLayout, String title, boolean isChecked, android.view.View.OnClickListener onClickListener) 
{ 
    final Button button = new Button(getContext()); 
    button.setText(title); 
    button.setTextSize(buttonTextSize); 
    final int buttonHeight = button.getHeight(); 
    setButtonChecked(button, isChecked); 
    button.setHeight(buttonHeight); 
    button.getBackground().setAlpha(buttonAlpha); 
    button.setOnClickListener(onClickListener); 
    linearLayout.addView(button, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); 
    return button; 
} 

public final void setButtonChecked(Button button, boolean isChecked) 
{ 
    button.setCompoundDrawablesWithIntrinsicBounds(Resources.getSystem().getIdentifier(isChecked ? "android:drawable/btn_check_on" : "android:drawable/btn_check_off", null, null), 0, 0, 0); 
} 

private boolean isMenuAlwaysOnTop = true; 
private PopupWindow popupWindowMenuV2 = null; 

public final void popupMenuNav2() 
{ 
    if (popupWindowMenuV2 == null) 
    { 
     // [start] layout 

     ScrollView scrollView = new ScrollView(this.getContext()); 

     final LinearLayout linearLayoutNavigation = new LinearLayout(this.getContext()); 
     linearLayoutNavigation.setOrientation(LinearLayout.VERTICAL); 
     linearLayoutNavigation.setBackgroundColor(0x7FFFFFFF); 
     linearLayoutNavigation.setPadding(20, 10, 20, 10); 

     scrollView.addView(linearLayoutNavigation, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); 

     popupWindowMenuV2 = new PopupWindow(this); 
     popupWindowMenuV2.setBackgroundDrawable(new BitmapDrawable()); 
     popupWindowMenuV2.setWidth(WindowManager.LayoutParams.WRAP_CONTENT); 
     popupWindowMenuV2.setHeight(WindowManager.LayoutParams.WRAP_CONTENT); 
     popupWindowMenuV2.setTouchable(true); 
     popupWindowMenuV2.setOutsideTouchable(!isMenuAlwaysOnTop); 
     popupWindowMenuV2.setFocusable(!isMenuAlwaysOnTop); 
     popupWindowMenuV2.setTouchInterceptor(new OnTouchListener() 
     { 
      @Override 
      public boolean onTouch(View v, MotionEvent event) 
      { 
       if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_OUTSIDE) 
       { 
        if (!isMenuAlwaysOnTop) 
         popupWindowMenuV2.dismiss(); 
        else 
         return false; 
        return true; 
       } 
       return false; 
      } 
     }); 
     popupWindowMenuV2.setContentView(scrollView); 

     // [end] layout 

     // [start] always on top checkbox 

     final Button buttonMenuAlwaysOnTop = addPopupCheckbox(linearLayoutNavigation, "always on top", isMenuAlwaysOnTop, null); 
     buttonMenuAlwaysOnTop.setOnClickListener(
       new OnClickListener() 
       { 
        @Override 
        public void onClick(View vv) 
        { 
         isMenuAlwaysOnTop = !isMenuAlwaysOnTop; 
         setButtonChecked(buttonMenuAlwaysOnTop, isMenuAlwaysOnTop); 
         popupWindowMenuV2.dismiss(); 
         popupWindowMenuV2.setOutsideTouchable(!isMenuAlwaysOnTop); 
         popupWindowMenuV2.setFocusable(!isMenuAlwaysOnTop); 
         popupWindowMenuV2.showAtLocation(((Activity) getContext()).getWindow().getDecorView(), Gravity.CENTER_VERTICAL + Gravity.RIGHT, 0, 0); 
        } 
       }); 

     // [end] always on top checkbox 

     addPopupButton(linearLayoutNavigation, "some button", 
       new OnClickListener() 
       { 
        @Override 
        public void onClick(View vv) 
        { 
         if (!isMenuAlwaysOnTop) 
          popupWindowMenuV2.dismiss(); 
         someAction(); 
        } 
       }); 

    } 

    popupWindowMenuV2.showAtLocation(((Activity) getContext()).getWindow().getDecorView(), Gravity.CENTER_VERTICAL + Gravity.RIGHT, 0, 0); 
} 

// somewhere in handler: 
      if (someCondition) 
      { 
       if (popupWindowMenuV2 != null && popupWindowMenuV2.isShowing()) 
        popupWindowMenuV2.dismiss(); 
       else 
        popupMenuNav2(); 
       return true; 
      } 
0

Przede wszystkim należy dowiedzieć się, że dlaczego popupWindow zostaje odrzucona po dotknięciu zewnątrz.

Po odczytać kodu źródłowego PopupWindow i styles.xml pliku zasobów,

<style name="Widget.PopupWindow"> 
    <item name="popupBackground">@drawable/editbox_dropdown_background_dark</item> 
    <item name="popupAnimationStyle">@style/Animation.PopupWindow</item> 
</style> 
<style name="Widget"> 
    <item name="textAppearance">?textAppearance</item> 
</style> 

Więc nie ma nic podobnego tematu dialogowym:

<style name="Theme.Dialog"> 
<item name="windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item> 
</style name="Theme.Dialog"> 

Ale Coś się stanie, gdy PopupWindow.setBackgroundDrawable () jest nazywany,

private void preparePopup(WindowManager.LayoutParams p) { 
    if (mContentView == null || mContext == null || mWindowManager == null) { 
     throw new IllegalStateException("You must specify a valid content view by " 
       + "calling setContentView() before attempting to show the popup."); 
    } 

    if (mBackground != null) { 
     final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams(); 
     int height = ViewGroup.LayoutParams.MATCH_PARENT; 
     if (layoutParams != null && 
       layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) { 
      height = ViewGroup.LayoutParams.WRAP_CONTENT; 
     } 

     // when a background is available, we embed the content view 
     // within another view that owns the background drawable 
     PopupViewContainer popupViewContainer = new PopupViewContainer(mContext); 
     PopupViewContainer.LayoutParams listParams = new PopupViewContainer.LayoutParams(
       ViewGroup.LayoutParams.MATCH_PARENT, height 
     ); 
     popupViewContainer.setBackgroundDrawable(mBackground); 
     popupViewContainer.addView(mContentView, listParams); 

     mPopupView = popupViewContainer; 
    } else { 
     mPopupView = mContentView; 
    } 
    mPopupViewInitialLayoutDirectionInherited = 
      (mPopupView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT); 
    mPopupWidth = p.width; 
    mPopupHeight = p.height; 
} 

Widok kontenera "PopupViewContainer" to c remedium.

private class PopupViewContainer extends FrameLayout { 
    private static final String TAG = "PopupWindow.PopupViewContainer"; 

    public PopupViewContainer(Context context) { 
     super(context); 
    } 


    @Override 
    public boolean dispatchTouchEvent(MotionEvent ev) { 
     if (mTouchInterceptor != null && mTouchInterceptor.onTouch(this, ev)) { 
      return true; 
     } 
     return super.dispatchTouchEvent(ev); 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     final int x = (int) event.getX(); 
     final int y = (int) event.getY(); 

     if ((event.getAction() == MotionEvent.ACTION_DOWN) 
       && ((x < 0) || (x >= getWidth()) || (y < 0) || (y >= getHeight()))) { 
      dismiss(); 
      return true; 
     } else if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { 
      dismiss(); 
      return true; 
     } else { 
      return super.onTouchEvent(event); 
     } 
    } 

}

Teraz znasz powód, który liczy. Istnieją zatem dwa sposoby na pozbycie się PopupWindow po dotknięciu na zewnątrz. 1. Tak jak zrobił to @Raaga. usuń pw.setBackgroundDrawable (new BitmapDrawable());

  1. można zaimplementować OnTouchListener do filtrowania zdarzeń touche poza PopupWindow.
Powiązane problemy