2012-05-02 4 views
10

Я хотел бы использовать PopupWindow со следующим поведением/особенностью:избежать PopupWindow увольнения после касания снаружи

  • Это фокусируемое (имеют интерактивные элементы управления внутри, например кнопка.)
  • The View «под» popupwindow имеет потреблять штрихи за пределами всплывающего окна правильно
  • .. но popupwindow должен остаться на экране даже после нажатия снаружи

Я нашел кучу сообщений, касающихся PopupWindo w, но никто из них не задал вопрос, как справиться с такой ситуацией.

Я думаю, что я пробовал все возможные комбинации setOutsideTouchable(), setFocusable(), setTouchable(), но я застрял. Popup имеет дело с щелчками на нем правильно, но он всегда убирается, когда касается снаружи.

Мой текущий код:

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

Моя общая цель состоит в том, чтобы создать плавающее окно, которое ведет себя как «инструменты палитры» в программном обеспечении, как канитель: есть некоторые элементы управления внутри, остается на вершине, пока они не будут закрыты Кнопка «X» и позволяет взаимодействовать с элементами управления снаружи под ним. Может быть, есть лучший способ сделать это, а не PopupWindow? Но я еще не нашел более подходящего контроля.

ответ

2

pw.setOutsideTouchable (false);

+2

Нет, что работает одинаково (всплывающее окно исчезает после нажатия на него снаружи, входя в onTouch). Как указано здесь: [link] (http://stackoverflow.com/questions/7271784/open-a-popupwindow-and-let-the-outides-still-touchable) настраиваемые всплывающие окна игнорируют setOutsideTouchable. –

6

Просто удалите pw.setBackgroundDrawable(new BitmapDrawable());

2

Попробуйте pw.setBackgroundDrawable (NULL);

7

это слишком поздно, но для людей, которые Google этот материал просто изменить порядок строк

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

вместо

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

положить что-нибудь после того, как метод showatlocation делает это, как ничто там

+0

Не работает .... работаю даже после переустановки для меня .. – charlie

0

можно установить Focusable (false) для PopupWindow

кнопок все еще интерактивные, но без визуального поведения щелчка (некоторые пользовательские обработчики, чтобы заставить показать щелчок?)

ниже образец плавающей окно с «всегда сверху» вариантом

оригинальным макетом возле окна с плавающим полностью функционировать в обоих случаях, кроме того, можно использовать диалоги и другие всплывающие окна, когда окно по-прежнему плавающей

также окно является многоразовым

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

Прежде всего, вы должны понять, что почему popupWindow уволен, когда вы касаетесь снаружи.

После чтения исходного кода PopupWindow и файловый ресурс styles.xml,

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

Так что нет ничего, как диалоговое тему:

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

Но Somethings случаются, когда PopupWindow.setBackgroundDrawable (),

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

Вид контейнера «PopupViewContainer» - это c reated.

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

}

Теперь вы знаете причину, которая имеет значение. Итак, есть два способа, с помощью которых вы можете отключить всплывающее окно PopoutWindow после касания снаружи. 1. просто как @Raaga сделал. Удалите pw.setBackgroundDrawable (новый BitmapDrawable());

  1. вы можете реализовать OnTouchListener для фильтрации событий, находящихся вне PopupWindow.
Смежные вопросы