触摸外面后避免PopupWindow被解雇

时间:2012-05-02 00:46:46

标签: android

我想使用具有以下行为/功能的PopupWindow:

  • 它是可聚焦的(例如,按钮内有交互式控件)
  • 'popupwindow下的视图'必须正确使用弹出窗口外的触摸
  • ..但是弹出窗口即使在外面点击
  • 之后也必须留在屏幕上

我发现了一些关于PopupWindow的帖子,但没有一个人质疑如何处理这种情况。

我想我尝试了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);

我的总体目标是创建一个浮动窗口,其行为类似于gimp等软件中的“工具调色板”:内部有一些控件,保持在顶部直到被“X”按钮关闭,并允许与外部控件进行交互它.. 也许有更好的方法来做到这一点,而不是PopupWindow?但我还是没有找到更合适的控制。

8 个答案:

答案 0 :(得分: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方法之后放任何东西都会让它像什么

答案 1 :(得分:6)

只需删除pw.setBackgroundDrawable(new BitmapDrawable());

即可

答案 2 :(得分:2)

pw.setOutsideTouchable(假);

答案 3 :(得分:2)

尝试

pw.setBackgroundDrawable(null);

答案 4 :(得分:2)

解决方案是:

popupWindow.setFocusable(真);

popupWindow.update();

感谢: http://android-er.blogspot.ch/2012/04/disable-outside-popupwindow-by.html

答案 5 :(得分:1)

首先,你必须弄明白当你触摸外面时popupWindow被解雇的原因。

阅读PopupWindow的源代码和资源文件styles.xml后,

if ($form->isValid()) {
    $securePass = $this->getUsersTable()->getUserByUsername( $this->params()->fromPost('username') );       
    if( $securePass ){   
        $bcrypt = new Bcrypt();
        if ($bcrypt->verify( $this->params()->fromPost( 'password' ) , $securePass->password ) ) {

            $sm          = $this->getServiceLocator();
            $dbAdapter   = $sm->get('Zend\Db\Adapter\Adapter');
            $authAdapter = new AuthAdapter(
                $dbAdapter,
                'users',
                'username',
                'password'
            );
            $authAdapter->setIdentity($securePass->username)
            ->setCredential($securePass->password);                           
            $result = $authAdapter->authenticate($authAdapter);

            $sesssionData = $authAdapter->getResultRowObject();

            $auth = new AuthenticationService();
            $storage = $auth->getStorage();
            $storage->write($sesssionData);

            return $this->redirect()->toRoute('user_list');
        }
    }
}



public function onBootstrap(MvcEvent $e)
{

    $eventManager        = $e->getApplication()->getEventManager();
    $moduleRouteListener = new ModuleRouteListener();
    $moduleRouteListener->attach($eventManager);
    $app            = $e->getParam('application');
    $app->getEventManager()->attach('render', array($this, 'setLayoutTitle'));
$eventManager->attach(MvcEvent::EVENT_DISPATCH, array($this, 'checkLogin'));
}

public function checkLogin(MvcEvent $e)
{
    $iden = new AuthenticationService();
    if( $iden->getIdentity() === NULL ){
        $matches    = $e->getRouteMatch();
        $controller = $matches->getParam('controller');
        $getController = explode( '\\', $controller );  

        if( isset( $getController[2] ) && $getController[2] != 'Login' ){
            $controller = $e->getTarget();
            return $controller->plugin('redirect')->toRoute('login');
        }
    }   
}

所以没有像对话主题那样:

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

但是当调用PopupWindow.setBackgroundDrawable()时会发生某些事情,

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

容器视图&#34; PopupViewContainer&#34;已创建。

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

}

现在你知道重要的原因了。 所以有两种方法可以让你在触摸外面后解除PopupWindow的解雇。 就像@Raaga那样。删除pw.setBackgroundDrawable(new BitmapDrawable());

  1. 您可以实现OnTouchListener来过滤PopupWindow之外的touche事件。

答案 6 :(得分:0)

可以为PopupWindow

设置setFocusable(false)

按钮仍然是可点击的,但没有可视点击行为(一些自定义处理程序强制显示点击?)

下面的

是浮动窗口的示例,其中“always on top”选项

在浮动窗口附近的原始布局在两种情况下都是完全可操作的,而且,当窗口仍然浮动时,可以使用对话框和其他弹出窗口

窗口也可以重复使用

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

答案 7 :(得分:0)

这里或其他地方似乎没有任何建议对我有用。所以我这样做了:

popupWindow.setTouchInterceptor(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (motionEvent.getX() < 0 || motionEvent.getX() > viewWidth) return true;
                if (motionEvent.getY() < 0 || motionEvent.getY() > viewHight) return true;

                return false;
            }
        });

如果触摸在popupWIndow的范围内,则不消耗触摸事件(因此按钮或滚动视图将起作用)。如果触摸超出范围,则触摸将被消耗并且不会传递给popupWindow,因此不会将其关闭。