I am trying to implement an expandable fab, I implemented it and it works as expected i.e when the user taps on fab_main the submenu becomes visible and active, and when the user taps on the fab_main again the sub menu turn invisible and inactive.
What My problem is that I want the submenu to close (in case it is open) when the user taps on screen like for example the current activity
I have Tried using ontouch (which didn't work) and dispatchTouchEvent(which worked but I was not able to use the sub menu buttons
This is my code for how I implemented expandable FAB
fab_main.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (isOpen) {
textView_img_edit.setVisibility(View.INVISIBLE);
textview_bg_edit.setVisibility(View.INVISIBLE);
fab2_bg_edit.startAnimation(fab_close);
fab1_img_edit.startAnimation(fab_close);
fab_main.startAnimation(fab_anti_clock_wise);
fab2_bg_edit.setClickable(false);
fab1_img_edit.setClickable(false);
isOpen = false;
} else {
textView_img_edit.setVisibility(View.VISIBLE);
textview_bg_edit.setVisibility(View.VISIBLE);
fab2_bg_edit.startAnimation(fab_open);
fab1_img_edit.startAnimation(fab_open);
fab_main.startAnimation(fab_clock_wise);
fab2_bg_edit.setClickable(true);
fab1_img_edit.setClickable(true);
isOpen = true;
}
}
});
I used this code in both onTouch and dispatchTouchEvent
if (isOpen) {
textView_img_edit.setVisibility(View.INVISIBLE);
textview_bg_edit.setVisibility(View.INVISIBLE);
fab2_bg_edit.startAnimation(fab_close);
fab1_img_edit.startAnimation(fab_close);
fab_main.startAnimation(fab_anti_clock_wise);
fab2_bg_edit.setClickable(false);
fab1_img_edit.setClickable(false);
isOpen = false;
}
Try setting a onTouchListener on the base layout. You can check for MotionEvent.ACTION_UP and close your fab submenu (if it's open) there.
Related
In my app I need to collapse ExpandableListView that already expanded when I press back button.
I can't find anything related online.
I have a large amount of data that should show in my expandable list view and I think it's so hard to collapse list by touching each Group manually.
Exp_List.setOnGroupCollapseListener(new OnGroupCollapseListener() {
#Override
public void onGroupCollapse(int groupPosition) {
Toast.makeText(getBaseContext(),Lessons_List.get(groupPosition)+ " is closed!", Toast.LENGTH_LONG).show();
}
});
Inside of onBackPressed, collapse all groups with a loop. If not groups collapsed, issue the default back press event:
#Override
public void onBackPressed() {
ExpandableListView elv;
boolean groupsCollapsed = false;
for (int i=0; i<elv.getCount(); ++i) {
if (elv.isGroupExpanded(i)) {
elv.collapseGroup(i);
groupsCollapsed = true;
}
}
// If no groups collapsed, call the default back button
if (!groupsCollapsed) {
super.onBackPressed();
}
}
When a PopupWindow is showing, clicking a button outside of PopupWindow's area only dismisses the PopupWindow, but the button's click listener doesn't respond. My question is, why doesn't the button's click listener respond?
private OnClickListener mSiftClickListener = new
View.OnClickListener() {
#Override
public void onClick(View v) {
if (mSiftPopwin != null && mSiftPopwin.isShowing()) {
ToastShow.makeText(mContext, "yes"); //never show
} else {
showSfitPopwin();
}
}
};
My onClickListener has two functions, showSiftPopwin and ToastShow, when Popwin is showing, click it again, Popwin dismiss but this onClick listener has't been invoked.
This is the expected behaviour.
A popup window will consume any touch events on the screen until it is dismissed. The touch event you mentioned does not get through to your button, and no click is performed.
You should move the button code into an OnDismissListener, if you want it to run whenever the window is dismissed.
An Android device configuration change (for example "slide the hard keyboard back in") will always call PhoneWindow.onConfigurationChanged(), which in turn, will call reopenMenu(). This will cause the menu of the currently running activity to be reopened, in case it is showing.
I have a lock on my menu implemented in my onPrepareOptionsMenu() override. The user must enter a code each time they want to see the menu. I don't want the user to be asked to enter the code again, while the menu is still up just because of a configuration change. Thus, I would like to know, is there any way I can check if the menu of current foreground activity is already showing? Knowing this, I could bypass asking for the access code if the menu is already up.
My custom workaround implementation is to use my own flag menuShowing, which I set in onPrepareOptionsMenu and reset in onOptionsItemSelected and in onKeyDown if the back button is clicked.
EDIT: It appears a screen orientation configuration change does not trigger this behavior. A hard keyboard slide however, does.
Until someone comes up with a nicer 'one call' answer, here is the custom workaround implementation that I mention in the question, with help from Sam's tips, in case someone needs the same functionality:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (showingMenu) {
// The menu button was clicked or the hard keyboard was
// slid open/closed while the menu was already showing
return true;
}
// Otherwise, either the menu was clicked or openOptionsMenu() was called
if (codeEntered) {
// Code was entered and then openOptionsMenu() was called
showingMenu = true;
// Menu will now be shown
return true;
} else {
// The menu button was clicked, ask for code
askForCode();
// Don't show menu yet
return false;
}
}
#Override
public void onOptionsMenuClosed(Menu menu) {
showingMenu = false;
codeEntered = false;
}
private void askForCode() {
codeEntered = getUserInput();
if (codeEntered)
openOptionsMenu();
}
getUserInput() actually occurs with the help of an AlertDialog and an EditText with an attached TextWatcher but the implementation details exceed the scope of this question, unless someone is interested.
In my case it´s
#Override
public void onPanelClosed(int featureId, Menu menu) {
showingMenu = false;
super.onPanelClosed(featureId, menu);
}
(Please note that the behavior described in this question only appeared because of something else seemingly unrelated we were doing. See the accepted answer.)
We have an Android activity with a GridView and a SlidingDrawer inside of a RelativeLayout. The way this activity responds to the trackball (or cursor keys) is rather odd. The focus will move among the items in the GridView, but whenever the cursor moves in a direction "out" of the GridView. (e.g. up when at the top, left when already at the leftmost item) the sliding drawer opens or shut. Notably, the focus stays on the same item in the GridView---it does not move to the sliding drawer.
With a trackball this is particularly horrible, as spinning the trackball past your real destination will cause the sliding drawer to repeatedly open and close.
We've determined that we can turn off the trackball entirely by overriding onTrackballEvent(). We'd prefer to have the trackball and cursor work normally on the GridView but not cause the sliding drawer to open or close. In principle we'd also like the trackball to focus on the various contents of the sliding drawer when it is open.
How?
You may consider creating custom views extending GridView and SlidingDrawer and using custom implementations of onInterceptTouchEvent and onTouchEvent for the GridView and a custom implementation just for onInterceptTouchEvent for the SlidingDrawer. You may not need to implement a custom SlidingDrawer depending on what user interactions may be triggered on the handle
for your custom GridView, give it an interface maybe defined like this:
public interface MyGridViewListener {
public boolean shouldPreventScroll();
}
return if your custom SlidingDrawer is opened. this returned value will be used to determine if actions should be performed(for onInterceptTouchEvent and onTouchEvent methods) on the GridView. So when the SlidingDrawer is opened, actions performed on the GridView will not trigger anything on the SlidingDrawer.
Activity:
MyGridView gridView = (MyGridView) findViewById(R.id.gridView);
gridView.setMyGridViewListener(new MyGridViewListener() {
#Override
public boolean shouldPreventScroll() {
return slidingDrawer.isOpened();
}
});
MyCustomGridView:
shouldIntercept will be called whenever some touch/track event happens on the GridView.
private boolean shouldIntercept() {
boolean shouldIntercept = false;
if(myGridViewListener != null) {
shouldIntercept = myGridViewListener.shouldPreventScroll();
}
return shouldIntercept;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return shouldIntercept() ? true : super.onInterceptTouchEvent(ev);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return shouldIntercept() ? true : super.onTouchEvent(ev);
}
#Override
public boolean onTrackballEvent(MotionEvent event) {
return shouldIntercept() ? true : super.onTrackballEvent(event);
}
public MyGridViewListener getMyGridViewListener() {
return myGridViewListener;
}
public void setMyGridViewListener(
MyGridViewListener myGridViewListener) {
this.myGridViewListener = myGridViewListener;
}
I hope this points you in a right direction or at least helps
While playing around with a custom sliding drawer I set the layout of the handle to some odd value, something like
handle.layout(0, 0,0, 0);
to make the handle disappear but dragging a finger from the side of the screen would still open the sliding drawer, which is what I didn't want, so I set
handle.layout(10000, 10000, 10000, 10000);
which moved it way outside the viewable area and the drawer could no longer be pulled out manually by dragging from the side of the screen. After looking at the source code its teh position of the handle that determines the sliding of the drawer, get rid of the handle and it should solve your problem.
If you need to open/close the drawer call animateOpen()/animateClose()
As it turned out, we caused this problem by an unrelated bit of foolishness. We wanted the MENU key to open and close the SlidingDrawer. We did this by overriding onPrepareOptionsMenu():
public boolean onPrepareOptionsMenu (Menu menu) {
slidingDrawer.animateToggle();
return true;
}
This works fine; but it turns out it can be called when the menu is not about to be opened. In particular, if the Activity uses setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT), then an unhandled key event will end up accessing the menu. This includes trackball motion off the edge of the screen.
The less dumb way to get the desired behavior is
public boolean onKeyUp(int keyCode, KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_MENU) {
slidingDrawer.animateToggle();
}
return super.onKeyUp(keyCode,event);
}
Meanwhile, we can get the trackball to move within the SlidingDrawer when it is open by setting up a SlidingDrawer.OnDrawerOpenListener which calls
slidingDrawer.getContent().requestFocus();
Finally it seems like a good idea to call
slidingDrawer.getHandle().setFocusable(false);
I would like to know how to prevent the menu bar from closing.
#Override
public void onOptionsMenuClosed(Menu menu) {
}
When the activity starts, I open the menu and want it to stay open.
new Handler().postDelayed(new Runnable() {
public void run() {
openOptionsMenu();
}
}, 1000);
You cannot keep the Options Menu open and it will always act that way. But what you can do is create your own custom menu in a layout.xml and set the visibility to GONE. Then, override the onKeyDown() method and listen for presses of the menu key. If it is pressed, the options menu will be set to open/close (VISIBLE/INVISIBLE) depending on its current state. That way, you can control if the options menu will remain open or not even after touch.