I'm implementing an activity with two action bar drawers.
Right now I have two buttons in the action bar which show these drawers and they are working fine. Even they close the other if already opened.
These drawers are intended to be used as filters (cities and categories) for a listview, and my idea is to listen for the OnClose event, so I can get the checked items and filter the list.
With "onDrawerClosed" I can do it very easy, but the problem is when drawers are shown via sliding, as the event is not fired.
I have been dealing then with "onDrawerSlide" and finally got this code:
void initDrawer() {
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.drawable.ic_home_up, R.string.app_name,
R.string.app_name) {
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
if (slideOffset == 0) {
//if (!drawerLayout.isDrawerOpen(drawerView)) {
outputManager.showToast("Closed ");
//drawerClosed(drawerView);
//}
invalidateOptionsMenu(); // calls onPrepareOptionsMenu()
}
super.onDrawerSlide(drawerView, slideOffset);
}
public void onDrawerClosed(View drawerView) {
// getActionBar().setTitle(mTitle);
// calling onPrepareOptionsMenu() to show action bar icons
invalidateOptionsMenu();
drawerClosed(drawerView);
}
public void onDrawerOpened(View drawerView) {
// getActionBar().setTitle(mDrawerTitle);
// calling onPrepareOptionsMenu() to hide action bar icons
invalidateOptionsMenu();
}
};
drawerLayout.setDrawerListener(drawerToggle);
}
It kept firing the event a lot (I think it's fired several times until sliding is completed), so I checked if slideOffset is 0. It neither works, one of the sliders works, but the other doesn't fire any event.
Any idea? Maybe I could block sliding and allow to display drawers only via buttons, but how?
Finally I removed the second drawer and came up with a different approach. I think I tried to use it in a way is not intended for.
Related
I am moving some menu items from the options menu to the navigation menu. My app uses a NavigationView that is populated by a menu as described at https://developer.android.com/reference/android/support/design/widget/NavigationView.html
One of the items calls webView.goBack() on the WebView in the main activity. When it was placed in the options menu, it was only enabled if webView.canGoBack(). Otherwise, it was disabled (grayed out). To accomplish this, onPrepareOptionsMenu() included the command:
back.setEnabled(webView.canGoBack());
As onPrepareOptionsMenu() is called every time the options menu is about to be displayed, this would update the status of the menu item to correctly reflect the state of the WebView.
However, I have not been able to replicate this behavior with the NavigationView. Is there a method or class similar to onPrepareOptionsMenu() that is called each time the NavigationView is prepared?
PS. Other people who have addressed similar questions have always referred to using a ListView, which was an older method of populating a navigation drawer. This question specifically relates to using a NavigationView with a menu.
The answer to this question is to add a DrawerListener and override onDrawerStateChanged.
// Create the navigation drawer.
drawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
// The `DrawerTitle` identifies the drawer in accessibility mode.
drawerLayout.setDrawerTitle(GravityCompat.START, getString(R.string.navigation_drawer));
// Listen for touches on the navigation menu.
final NavigationView navigationView = (NavigationView) findViewById(R.id.navigationView);
navigationView.setNavigationItemSelectedListener(this);
// Get handles for `navigationMenu` and the back and forward menu items. The menu is zero-based, so item 1 and 2 and the second and third items in the menu.
final Menu navigationMenu = navigationView.getMenu();
final MenuItem navigationBackMenuItem = navigationMenu.getItem(1);
final MenuItem navigationForwardMenuItem = navigationMenu.getItem(2);
// The `DrawerListener` allows us to update the Navigation Menu.
drawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
}
#Override
public void onDrawerOpened(View drawerView) {
}
#Override
public void onDrawerClosed(View drawerView) {
}
#Override
public void onDrawerStateChanged(int newState) {
// Update the back and forward menu items every time the drawer opens.
navigationBackMenuItem.setEnabled(webView.canGoBack());
navigationForwardMenuItem.setEnabled(webView.canGoForward());
}
});
NavigationView exposes its underlying Menu with getMenu(). You can use that to find menu items and make changes to them.
I want to develop an application that can be 100% functional even using a dpad, but not for TV devices, so I don't want to rely on Leanback library. I have already followed the guidelines here in order to focus the proper elements of my UI.
I am using the support design library and I'm having several issues with my NavigationView:
When I open the drawer for the first time, it has the first item checked, but another item focused
If I close and open the drawer again, there is no item checked and focus is lost
This is what I'm doing to handle the focus:
private void initDrawer(){
drawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
navigationView = (NavigationView)findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(this);
drawerToggle = new ActionBarDrawerToggle(MainActivity.this, drawerLayout, R.string.app_name, R.string.app_name){
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
//This is not working properly
navigationView.requestFocus();
}
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
//This seems to work
mContentLayout.requestFocus();
}
};
drawerLayout.setDrawerListener(drawerToggle);
}
This is what I'm doing to toggle the drawer opening/closing using an hardware button:
#Override
public boolean onKeyUp(int keyCode, KeyEvent event){
if(keyCode==KeyEvent.KEYCODE_BUTTON_Y){
drawerToggle.syncState();
if(drawerLayout.isDrawerOpen(GravityCompat.START)){
drawerLayout.closeDrawer(GravityCompat.START);
}
else {
drawerLayout.openDrawer(GravityCompat.START);
}
return true;
}
else return super.onKeyUp(keyCode, event);
}
I would like to focus the first item on the NavigationView everytime I open the drawer. What am I missing?
This is a known bug of design support library, apparently.
Google claims it's been fixed in 23.1.1 but it doesn't work.
I had to make these changes in my onDrawerOpened method:
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
if(navigationView.requestFocus()){
NavigationMenuView navigationMenuView = (NavigationMenuView)navigationView.getFocusedChild();
navigationMenuView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
}
}
In my application, I'm using a Navigation Drawer. I have given each item in the Navigation Drawer a different Icon for opening the Nav Drawer.
When I initially start the app, the drawer icon for the first fragment animates like normal. But when I click on another Nav Drawer Item, the animations break.
In my MainActivity, I have this code for toggling the nav drawer:
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ab_mytasks, R.string.drawer_open,
R.string.drawer_close) {
public void onDrawerClosed(View view) {
getActionBar().setTitle(mTitle);
invalidateOptionsMenu(); // creates call to
// onPrepareOptionsMenu()
}
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(mDrawerTitle);
invalidateOptionsMenu(); // creates call to
// onPrepareOptionsMenu()
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
mDrawerToggle.syncState();
Then in each of my fragments, I have this code for setting the custom icon:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
final ActionBar actionBar = getActivity().getActionBar();
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setHomeAsUpIndicator(R.drawable.ab_mytasks);
}
I have tried putting in the same mDrawerToggle method as in my MainActivity into my fragments. But the app crashes when I use getActivity().invalidateOptionsMenu().
Here is an image representation of my problem:
1 = Animation works as normal
2 = Selected another fragment from Nav Drawer
3 = Original Fragment icon animation is broken
When you change the icon (setHomeAsUpIndicator) you will no longer get an animation.
I'm currently trying to modify the UI of an existing Android application by making some slight changes. One change I need to implement is to modify the navigation drawer / slider toggle icon between one of 3 icons (on, off, 'special'). You supply the icon on creation of the ActionBarDrawerToggle on instantiation and there doesn't seem to be a method to modify the value after the object is created. Does anyone know if it's possible to achieve this (hack or no hack) ?
Thanks in advance,
thisguy
Check out this guide here: http://www.androidhive.info/2013/11/android-sliding-menu-using-navigation-drawer/
and here: http://developer.android.com/training/implementing-navigation/nav-drawer.html
I think you may change icon on ActionBarDrawerToggle's methods:
/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
getActionBar().setTitle(mTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
getActionBar().setTitle(mDrawerTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
};
Is there any way to make sure that the navigation drawer stays on top of the content in the fragment?
I created a small test application with dummy data. 10 fragments with a corresponding numbered button and textview. The issue is with the fact that the fragment elements seem to have higher priority than the navigation drawer.
As seen in the screenshot, once I attempt to open up the "0 fragment" it instead opts to register the click on the button behind the navigation drawer. Pressing any other content item works fine, but this is as long as there are no other interactable items beneath them. What can I do to have the navigation drawer properly stay on top of the content behind it?
Set android:clickable="true" tag on sliding pane layout.
The problem seem not because of click focus,
Visit https://developer.android.com/training/implementing-navigation/nav-drawer.html#DrawerLayout
The main content view (the FrameLayout above) must be the first child in the DrawerLayout because the XML order implies z-ordering and the drawer must be on top of the content.
In my fragment drawer, I set TouchListener to return True.
It worked for me
mFragmentContainerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
I solved it in a different way.
Here is my code for setting up the Drawer:
/**
* Setup Navigation Drawer
*/
private void setDrawer() {
NavigationDrawerFragment mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.fragment_drawer);
mNavigationDrawerFragment.setup(R.id.fragment_drawer, (DrawerLayout) findViewById(R.id.drawer), mToolbar);
}
the setup method is inside my NavigationDrawerFragment, here is my code for it:
/**
* Users of this fragment must call this method to set up the navigation drawer interactions.
*
* #param fragmentId The android:id of this fragment in its activity's layout.
* #param drawerLayout The DrawerLayout containing this fragment's UI.
* #param toolbar The Toolbar of the activity.
*/
public void setup(int fragmentId, DrawerLayout drawerLayout, Toolbar toolbar) {
View mFragmentContainerView = (View) getActivity().findViewById(fragmentId).getParent();
DrawerLayout mDrawerLayout = drawerLayout;
//noinspection deprecation
mDrawerLayout.setStatusBarBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));
ActionBarDrawerToggle mActionBarDrawerToggle = new ActionBarDrawerToggle(getActivity(), mDrawerLayout, toolbar, "Drawer opened", "Drawer closed") {
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
if (!isAdded()) return;
// Solution:
// Disable click event on views below Navigation Drawer
mFragmentContainerView.setClickable(false);
getActivity().invalidateOptionsMenu();
}
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
if (!isAdded()) return;
// Solution:
// Enable click event on views below Navigation Drawer
mFragmentContainerView.setClickable(true);
getActivity().invalidateOptionsMenu();
}
};
// Defer code dependent on restoration of previous instance state.
mDrawerLayout.post(new Runnable() {
#Override
public void run() {
mActionBarDrawerToggle.syncState();
}
});
//noinspection deprecation
mDrawerLayout.setDrawerListener(mActionBarDrawerToggle);
}
That's it
You have to set clickable, focusable and focusableInTouchMode in the highest view of your drawer's layout.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true">
Well, I found one solution for this issue. When the drawer is being opened you can bring the nav bar to the front by calling the bringToFront()-method on the layout you use. This makes sure the navigation drawer stays on top of any underlying content until a new item has been selected.
I.e:
#Override
public void onDrawerOpened(View drawerView)
{
activity.getActionBar().setTitle("Select content");
activity.invalidateOptionsMenu();
drawerLayout.bringToFront();
}