Hi.
Here's my problem. I use the drawer in an activity class and I launch a fragment when I click on a button of the activity layout.
When I launch the fragment, I change the drawer icon to back arrow but when I click on the back arrow, the drawer menu opens.
It is possible to change/override the listener of the back arrow in order to change the behavior and put an onBackPressed() instead of opening the drawer.
Sorry if someone already asked this..
Thanks a lot!
Hi, it seems that when you click on the navigation icon / back arrow, it will not trigger a traditional onOptionsItemSelected method.
This is my solution:
drawerBuilder.withOnDrawerNavigationListener(new Drawer.OnDrawerNavigationListener() {
@Override
public boolean onNavigationClickListener(View clickedView) {
Toast.makeText(Activity800.this, "HERE", Toast.LENGTH_SHORT).show();
return true;
}
}).build();
You can see the source code of DrawerBuilder.handleDrawerNavigation()
The problem with this solution is that you have to declare the listener when you instantiate the Drawer (in the activity). But I want to change the behavior when I am on the fragment and when I change the drawer icon to back arrow.
But can we know which icon is set in the onNavigationClickListener ?
Thanks!
Here is a simple Activity, hole can help you.
public class Activity802 extends ...{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//build your drawer ...
//...
drawerBuilder.withOnDrawerNavigationListener(new Drawer.OnDrawerNavigationListener() {
@Override
public boolean onNavigationClickListener(View clickedView) {
//In our case this method is always called with getSupportFragmentManager().getBackStackEntryCount() > 0 because of our addOnBackStackChangedListener
//if (getSupportFragmentManager().getBackStackEntryCount() > 0) {//can go back
onBackPressed();
//}
return true;
}
}).build();
//...
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
//change to back arrow
drawer.getActionBarDrawerToggle().setDrawerIndicatorEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//if you dont want the drawer to be opened in Fragment
drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
} else {
//change to hamburger icon
drawer.getActionBarDrawerToggle().setDrawerIndicatorEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
//call this method to display hamburger icon
drawer.getActionBarDrawerToggle().syncState();
drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
}
}
});
}
@OnClick(R.id.btn)
public void onBtn() {
getSupportFragmentManager().beginTransaction().replace(R.id.fl, new F()).addToBackStack(null).commit();
}
public static class F extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.activity_main, container, false);
}
}
}
You can see the source code of com.mikepenz.materialdrawer.DrawerBuilder.handleDrawerNavigation() to get more information.
I don't really understand why you have to implement this function:
@OnClick(R.id.btn)
public void onBtn() {
getSupportFragmentManager().beginTransaction().replace(R.id.fl, new F()).addToBackStack(null).commit();
}
Otherwise, when I am on my fragment and I go back, the onBackStackChanged() isn't called and I return not to the activity that launch the fragment.
Hi, onBtn() is for launching a fragment. In my activity layout, there is a button with id R.id.btn, when click it, this method will be called. (Is this different from how you launching a fragment?)
The onBackStackChanged should be called, check if you have called "addToBackStack" when launch a fragment, and your Fragment(android.app.Fragment or android.support.v4.Fragment) should fit with its FragmentManager (getFragmentManager() or getSupportFragmentManager())
Can you give some codes? Maybe I didn't well understand your problem.
Well,
My main activity is:
public class SettingsActivity extends AppCompatActivity implements Drawer.OnDrawerItemClickListener, UserListener{
private Toolbar toolbar;
private DrawerMenuUtils drawerMenuUtils;
private Drawer drawer;
private TextView account;
private TextView notifications;
private NotificationFragment notificationFragment;
private AccountFragment accountFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
toolbar = (Toolbar) findViewById(R.id.settings_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setTitle(R.string.settings);
buildDrawer(savedInstanceState);
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
//change to back arrow
drawer.getActionBarDrawerToggle().setDrawerIndicatorEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//if you dont want the drawer to be opened in Fragment
drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
} else {
//change to hamburger icon
drawer.getActionBarDrawerToggle().setDrawerIndicatorEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
//call this method to display hamburger icon
drawer.getActionBarDrawerToggle().syncState();
drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
}
}
});
account = (TextView) findViewById(R.id.settings_account);
account.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
accountFragment = new AccountFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(R.id.settings_frame_container, accountFragment);
transaction.addToBackStack(null);
transaction.commit();
}
});
notifications = (TextView) findViewById(R.id.settings_notifications);
notifications.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
notificationFragment = new NotificationFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(R.id.settings_frame_container, notificationFragment);
transaction.addToBackStack(null);
transaction.commit();
}
});
}
private void buildDrawer(Bundle savedInstanceState){
PrimaryDrawerItem profil = new PrimaryDrawerItem().withName("Profile");
SecondaryDrawerItem planning = new SecondaryDrawerItem().withName("Agenda");
SecondaryDrawerItem recommandations = new SecondaryDrawerItem().withName("Explore");
SecondaryDrawerItem settings = new SecondaryDrawerItem().withName("Settings");
SecondaryDrawerItem login;
User user = Application.getUserHelper().getCurrentUser();
if (user == null) {
login = new SecondaryDrawerItem().withName("Log in");
user = new User();
user.setUsername("Anonyme");
user.setEmail("[email protected]");
} else {
login = new SecondaryDrawerItem().withName("Log out");
}
AccountHeader accountHeader = new AccountHeaderBuilder()
.withActivity(this)
.withHeaderBackground(R.color.grayQ)
.addProfiles(
new ProfileDrawerItem().withName(user.getUsername()).withEmail(user.getEmail())
)
.withSelectionListEnabledForSingleProfile(false)
.build();
drawer = new DrawerBuilder().withActivity(this).withToolbar(toolbar)
.addDrawerItems(
profil,
planning,
recommandations,
new DividerDrawerItem(),
settings,
login
).withSavedInstance(savedInstanceState)
.withAccountHeader(accountHeader)
.withOnDrawerItemClickListener(this)
.withOnDrawerNavigationListener(new Drawer.OnDrawerNavigationListener() {
@Override
public boolean onNavigationClickListener(View view) {
onBackPressed();
return true;
}
})
.build();
drawer.setSelection(-1);
}
@Override
public boolean onItemClick(View view, int i, IDrawerItem iDrawerItem) {
switch (i) {
case 1:
if (!(drawer.getCurrentSelection() == 1)) {
Intent profileIntent = new Intent(Application.getContext(), ProfileActivity.class);
startActivity(profileIntent);
}
break;
case 2:
if (!(drawer.getCurrentSelection() == 2)) {
Intent agendaIntent = new Intent(Application.getContext(), MainActivity.class);
startActivity(agendaIntent);
}
break;
case 3:
if (!(drawer.getCurrentSelection() == 3)) {
Intent exploreIntent = new Intent(Application.getContext(), ExploreActivity.class);
startActivity(exploreIntent);
}
break;
case 5:
if (!(drawer.getCurrentSelection() == 5)) {
Intent settingsIntent = new Intent(Application.getContext(), SettingsActivity.class);
startActivity(settingsIntent);
}
break;
case 6:
if (Application.getUserHelper().getCurrentUser() == null) {
Intent loginIntent = new Intent(Application.getContext(), LoginActivity.class);
startActivity(loginIntent);
} else {
Application.getUserHelper().logout(this);
}
break;
default:
return false;
}
return false;
}
//...
@Override
public void onError(Throwable t) {
Toast.makeText(Application.getContext(), "No connected account ?", Toast.LENGTH_LONG).show();
}
}
Here the AccountFragment:
public class AccountFragment extends Fragment {
private View rootView;
private TextView emailView;
private TextView usernameView;
private TextView changePassword;
private TextView socialNetwork;
private ImageView twitterView;
private Button logInButton;
private User user;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_account, container, false);
emailView = (TextView) rootView.findViewById(R.id.settings_email_response);
usernameView = (TextView) rootView.findViewById(R.id.settings_username_response);
changePassword = (TextView) rootView.findViewById(R.id.settings_change_password);
socialNetwork = (TextView) rootView.findViewById(R.id.settings_socail_network);
twitterView = (ImageView) rootView.findViewById(R.id.twitter_icon);
logInButton = (Button) rootView.findViewById(R.id.login_button);
logInButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Application.getContext(), LoginActivity.class);
startActivity(intent);
}
});
((SettingsActivity) getActivity()).getSupportActionBar().setTitle(R.string.my_account);
return rootView;
}
@Override
public void onStart() {
super.onStart();
user = Application.getUserHelper().getCurrentUser();
if (user == null) {
user = new User();
user.setUsername("Anonyme");
user.setEmail("[email protected]");
changePassword.setVisibility(View.GONE);
socialNetwork.setVisibility(View.GONE);
twitterView.setVisibility(View.GONE);
logInButton.setVisibility(View.VISIBLE);
}
emailView.setText(user.getEmail());
usernameView.setText(user.getUsername());
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case android.R.id.home:
getActivity().onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
I'm using the android.support.v4.app.FragmentManager but the icon isn't changing when I am in the Fragment (and drawer listener is already the same).
The drawer icon now is set by OnBackStackChangedListener.onBackStackChanged method.
Make sure this method is called when your backstack changed.
But you use different FragmentManagers in the above codes. You should always use the same FragmentManager.
You're right ! I had to use getSupportFragmentManager.
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
It works, thanks a lot!
Hi again !
Got an another problem... When I try to add drawer.setSelection(settings) instead of drawer.setSelection(-1) after the build, my app freeze and crash.
drawer = new DrawerBuilder().withActivity(this).withToolbar(toolbar)
.addDrawerItems(
profil,
planning,
recommandations,
new DividerDrawerItem(),
settings,
login
).withSavedInstance(savedInstanceState)
.withAccountHeader(accountHeader)
.withOnDrawerItemClickListener(this)
.withOnDrawerNavigationListener(new Drawer.OnDrawerNavigationListener() {
@Override
public boolean onNavigationClickListener(View view) {
onBackPressed();
return true;
}
})
.build();
drawer.setSelection(settings);
I tried to put drawer.setSelection(5) but it's not working.
How can I fix this ?
Sorry again to bother you!
What is your settings's class? PrimaryDrawerItem ?
drawer.setSelection() use the item's identifier. use settings.withIdentifier( a int to identify this item).
And is there any exception information after your app crash?
No, it's a SecondaryDrawerItem :
private void buildDrawer(Bundle savedInstanceState){
PrimaryDrawerItem profil = new PrimaryDrawerItem().withName("Profile");
SecondaryDrawerItem planning = new SecondaryDrawerItem().withName("Agenda");
SecondaryDrawerItem recommandations = new SecondaryDrawerItem().withName("Explore");
SecondaryDrawerItem settings = new SecondaryDrawerItem().withName("Settings");
SecondaryDrawerItem login;
User user = Application.getUserHelper().getCurrentUser();
if (user == null) {
login = new SecondaryDrawerItem().withName("Log in");
user = new User();
user.setUsername("Anonyme");
user.setEmail("[email protected]");
} else {
login = new SecondaryDrawerItem().withName("Log out");
}
AccountHeader accountHeader = new AccountHeaderBuilder()
.withActivity(this)
.withHeaderBackground(R.color.grayQ)
.addProfiles(
new ProfileDrawerItem().withName(user.getUsername()).withEmail(user.getEmail())
)
.withSelectionListEnabledForSingleProfile(false)
.build();
drawer = new DrawerBuilder().withActivity(this).withToolbar(toolbar)
.addDrawerItems(
profil,
planning,
recommandations,
new DividerDrawerItem(),
settings,
login
).withSavedInstance(savedInstanceState)
.withAccountHeader(accountHeader)
.withOnDrawerItemClickListener(this)
.withOnDrawerNavigationListener(new Drawer.OnDrawerNavigationListener() {
@Override
public boolean onNavigationClickListener(View view) {
onBackPressed();
return true;
}
})
.build();
drawer.setSelection(settings);
}
No information after the app crash.
I'll try to use settings.withIdentifier(int) and I'll let you know.
Thanks again.
When the app freeze, I got :
11-11 17:12:23.907 515-515/pachageName I/Timeline? Timeline: Activity_launch_request id:pachageName time:135045853
11-11 17:12:24.107 515-515/packageName I/Timeline? Timeline: Activity_launch_request id:packageName time:135046056
11-11 17:12:24.357 515-515/packageName I/Timeline? Timeline: Activity_launch_request id:packageName time:135046304
11-11 17:12:24.527 515-515/packageName I/Timeline? Timeline: Activity_launch_request id:packageName time:135046478
11-11 17:12:24.717 515-515/packageName I/Timeline? Timeline: Activity_launch_request id:packageName time:135046666
11-11 17:12:24.868 515-515/packageName I/Timeline? Timeline: Activity_launch_request id:packageName time:135046815
11-11 17:12:25.098 515-515/packageName I/Timeline? Timeline: Activity_launch_request id:packageName time:135047044
...
I tried to use settings.withIdentifier(int) but it's not working.
I proceed like that:
private void buildDrawer(Bundle savedInstanceState) {
PrimaryDrawerItem profil = new PrimaryDrawerItem().withName("Profile").withIdentifier(0);
SecondaryDrawerItem planning = new SecondaryDrawerItem().withName("Agenda").withIdentifier(1);
SecondaryDrawerItem recommandations = new SecondaryDrawerItem().withName("Explore").withIdentifier(2);
SecondaryDrawerItem settings = new SecondaryDrawerItem().withName("Settings").withIdentifier(3);
SecondaryDrawerItem login;
User user = QualityShowApplication.getUserHelper().getCurrentUser();
if (user == null) {
login = new SecondaryDrawerItem().withName("Log in").withIdentifier(4);
user = new User();
user.setUsername("Anonyme");
user.setEmail("[email protected]");
} else {
login = new SecondaryDrawerItem().withName("Log out").withIdentifier(4);
}
AccountHeader accountHeader = new AccountHeaderBuilder()
.withActivity(this)
.withHeaderBackground(R.color.grayQ)
.addProfiles(
new ProfileDrawerItem().withName(user.getUsername()).withEmail(user.getEmail())
)
.withSelectionListEnabledForSingleProfile(false)
.build();
drawer = new DrawerBuilder().withActivity(this).withToolbar(toolbar)
.addDrawerItems(
profil,
planning,
recommandations,
new DividerDrawerItem(),
settings,
login
).withSavedInstance(savedInstanceState)
.withAccountHeader(accountHeader)
.withOnDrawerItemClickListener(this)
.withOnDrawerNavigationListener(new Drawer.OnDrawerNavigationListener() {
@Override
public boolean onNavigationClickListener(View view) {
onBackPressed();
return true;
}
})
.build();
drawer.setSelection(settings); // drawer.setSelection(3) also tried
//...
@Fanalys you use the latest version?
Well I use the 4.4.4.
But I've just noticed that the 4.4.6 is available. The new version include fix about setSelection(...) ?
@Fanalys what happens in your withOnDrawerItemClickListener?
The setSelection() method triggers this method
I launch my different activities in the withOnDrawerItemClickListener :
@Override
public boolean onItemClick(View view, int i, IDrawerItem iDrawerItem) {
switch (i) {
case 1:
if (!(drawer.getCurrentSelection() == 1)) {
Intent profileIntent = new Intent(Application.getContext(), ProfileActivity.class);
startActivity(profileIntent);
}
break;
case 2:
if (!(drawer.getCurrentSelection() == 2)) {
Intent agendaIntent = new Intent(Application.getContext(), MainActivity.class);
startActivity(agendaIntent);
}
break;
case 3:
if (!(drawer.getCurrentSelection() == 3)) {
Intent exploreIntent = new Intent(Application.getContext(), ExploreActivity.class);
startActivity(exploreIntent);
}
break;
case 5:
if (!(drawer.getCurrentSelection() == 5)) {
Intent settingsIntent = new Intent(Application.getContext(), SettingsActivity.class);
startActivity(settingsIntent);
}
break;
case 6:
if (Application.getUserHelper().getCurrentUser() == null) {
Intent loginIntent = new Intent(Application.getContext(), LoginActivity.class);
startActivity(loginIntent);
} else {
Application.getUserHelper().logout(this);
}
break;
default:
return false;
}
return false;
}
why do you check for the current selection there? the drawerItem comes with the identifier you have set.
so depending on the drawerItem which was selected you then launch the activity. no need to check if they were already selected.
could you please provide a log messages which shows the crash? you produce an endless loop somewhere. probably disable the listener to try if it happens there?
I check the current selection because I don't want that a new activity starts if the user is already on this activity.
I don't really have a crash app but she's freezing and I can't use it. In my console, I have :
11-11 17:12:23.907 515-515/pachageName I/Timeline? Timeline: Activity_launch_request id:pachageName time:135045853
11-11 17:12:24.107 515-515/packageName I/Timeline? Timeline: Activity_launch_request id:packageName time:135046056
11-11 17:12:24.357 515-515/packageName I/Timeline? Timeline: Activity_launch_request id:packageName time:135046304
11-11 17:12:24.527 515-515/packageName I/Timeline? Timeline: Activity_launch_request id:packageName time:135046478
11-11 17:12:24.717 515-515/packageName I/Timeline? Timeline: Activity_launch_request id:packageName time:135046666
11-11 17:12:24.868 515-515/packageName I/Timeline? Timeline: Activity_launch_request id:packageName time:135046815
11-11 17:12:25.098 515-515/packageName I/Timeline? Timeline: Activity_launch_request id:packageName time:135047044
...
But it gives no useful information. I tried to get more information, I'll try to avoid the listener and see what happens.
It works when I use setSelection(settings, false) !
so you produce an endless loop somewhere when you fire the on item click event
Yes because I launch my activity which builds the drawer. Then I set the selection to this activity. The withOnDrawerItemClickListener instantiate a new activity which builds again the drawer etc. etc.. !
Thanks for the help :+1:
no problem
thanks @xzchaoo for helping
True, thanks @xzchaoo (and you too @mikepenz ;)) !
Most helpful comment
Hi, it seems that when you click on the navigation icon / back arrow, it will not trigger a traditional onOptionsItemSelected method.
This is my solution:
You can see the source code of DrawerBuilder.handleDrawerNavigation()