Task

  • When you click the FloatingActionButton button should turn (resulting in the "plus sign - add" icon to "cross - cancel") and a popupWindow pop-up window should appear;
  • When the FloatingActionButton pressed again, the button should return to its original position, and the window should disappear.
  • The same should happen when you popupWindow outside the popupWindow zone popupWindow

The first two items are fully implemented via OnClickListener() . To implement the third one, there is the PopupWindow.OnDismissListener() method, but one thing is that it “ PopupWindow.OnDismissListener() button” on the button, which is the source of the problem discussed in this question.

Decision

 private void initFAB(){ fab = (FloatingActionButton) findViewById(R.id.fab); //... final PopupWindow popupWindow = new PopupWindow(popup_window, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); // Срабатывает только при нажатии на кнопку fab.setOnClickListener(new View.OnClickListener() { // Триггер; в начальном состоянии окно убрано boolean fABShowMenu = false; public void onClick(View view) { popupWindow.setOutsideTouchable(true); if (!fABShowMenu){ // должно выполняться, когда окно убрано rotateFabForward(); popupWindow.showAtLocation(fab, Gravity.END | Gravity.BOTTOM, 50, 400); fABShowMenu = true; // теперь окно показано } else{ // должно выполняться, когда окно показано rotateFabBackward(); popupWindow.dismiss(); fABShowMenu = false; // теперь онко убрано } } }); popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() { @Override public void onDismiss(){ rotateFabBackward(); //fABShowMenu = false; } }); } 

This solution works, but if you close the window by touching it outside, then pressing the button again will not open it, because the fABShowMenu trigger is still true; .

  • Ideally, to solve the problem, you need one thing: from the setOnDismissListener method setOnDismissListener change the value of fABShowMenu = false; . But you can not - this is a local variable of another method.
  • We cannot declare a variable without initialization outside the setOnClickListener method — it will Variable ... accessed from within inner class, needs to be declared final . To make it final without initialization is meaningless, and if initialized, then at the input if (!fABShowMenu){ condition will always be !false , that is, true .
  • You setOnDismissListener push setOnDismissListener inside OnClickListener() , but then when you press the button in order to close the menu, two events will “shoot” at once - Dismiss and Click . As the experiment shows, onDismiss returns false , then the onClick will work with this value at the input and in the else (where we need) we do not get.

Anything can be done without fundamentally changing the decision?


Update

Ideally, to solve the problem, you need one thing: from the setOnDismissListener method setOnDismissListener change the value of fABShowMenu = false; .

I beg your pardon, nonsense said. Even if in some incredible way I did what I said, then the onClick method will be onClick , in which we come with fABShowMenu = false; and the menu will open immediately. When you press FAB when the menu is open, two events occur, and that’s the problem.

  • 3
    Because for some reason you keep the state inside the listeners. You have, de facto, a finite state machine describing the state of this menu, and UI listeners who should control it, calling open, close, toggle and / or analogs, but the menu control handle itself should be completely separate from the listeners. - etki

1 answer 1

Any UI element in Android has a tag field that is perfect for cases like yours. Those. the button itself will store the state of the secondary element and this value can be changed from wherever the button itself is available.
fABShowMenu can fABShowMenu variable altogether, and set the initial state directly in the XML markup.

  • Thank you for your reply! I will try to implement - then I appreciate your answer. - Gleb
  • I tried with tagami. Everything works, as you said, but the main problem remains: when you click on a button to close the menu, two events occur at once: Dismiss and Click . Probably, this already claims a separate question. - Bokov Gleb
  • OnDismissListener dynamically set and remove when necessary, so that there are no unnecessary positives. - Eugene Krivenja