Вопрос по android – Предотвращение увольнения PopupWindow после прикосновения снаружи

12

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

It is focusable (has interactive controls inside eg. buttons) The View 'under' popupwindow has to consume the touches outside the popup properly .. but the popupwindow has to stay on screen even after clicking outside

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

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

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

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

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

Ваш Ответ

7   ответов
2

popupWindow.setFocusable (истина);

popupWindow.update ();

Благодаря: http://android-er.blogspot.ch/2012/04/disable-outside-popupwindow-by.html

2

Error: User Rate Limit ExceededlinkError: User Rate Limit Exceeded Michał Wróbel
7

просто измените порядок строк

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 делает это как ничего

Error: User Rate Limit Exceeded
0

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

ниже приведен пример для плавающего окна с надписью «всегда сверху» вариант

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

также окно многоразовое

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

Пытаться

pw.setBackgroundDrawable(null);
6

pw.setBackgroundDrawable(new BitmapDrawable());

1

вы должны выяснить, почему всплывающее окно закрывается при касании снаружи.

После прочтения исходного кода 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">

Но что-то происходит, когда вызывается PopupWindow.setBackgroundDrawable (),

private void preparePopup(WindowManager.LayoutParams p) {
    if (mContentView == null || mContext == null || mWindowManager == null) {
        throw new IllegalStateException("You must sp,ecify 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;
}

Представление контейнера & quot; PopupViewContainer & quot; создано.

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

}

Теперь вы знаете причину, которая имеет значение. Таким образом, есть два способа избежать отклонения PopupWindow после прикосновения снаружи. 1. Так же, как @Raaga. удалить pw.setBackgroundDrawable (new BitmapDrawable ());

you can implement a OnTouchListener to filter the touche events outside the PopupWindow.

Похожие вопросы