i want to replace one menu with another, in this view i have items home,products and so on.. , while clicking on products it opens another menu containing diff products.In the below code i am trying to replace another menu,but i m getting null pointer exception, but i want know that on clicking navigation item how i can switch to another navigation view?
Can anyone suggest what to do in this situation?I have attached logcat snapshot.
public void selectDrawerItem(MenuItem menuItem)
{
// Create a new fragment and specify the fragment to show based on nav item clicked
Fragment fragment = null;
Class fragmentClass;
switch(menuItem.getItemId())
{
case R.id.menu_home:
fragmentClass = A.class;
break;
case R.id.menu_products:
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.getMenu().clear();
navigationView.inflateMenu(R.menu.menu_products);
break;
case R.id.menu_B:
fragmentClass = B.class;
break;
case R.id.menu_C:
fragmentClass = C.class;
break;
case R.id.menu_D:
fragmentClass = d.class;
break;
case R.id.menu_E:
fragmentClass = E.class;
break;
case R.id.menu_F:
fragmentClass = F.class;
break;
default:
fragmentClass = A.class;
}
try
{
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e)
{
e.printStackTrace();
}
// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getSupportFragmentManager();
//this is line 155:
fragmentManager.beginTransaction().replace(R.id.frame, fragment).commit();
// Highlight the selected item has been done by NavigationView
menuItem.setChecked(true);
// Set action bar title
setTitle(menuItem.getTitle());
// Close the navigation drawer
drawer.closeDrawers();
}
private void setupDrawerContent(NavigationView navigationView){
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener()
{
#Override
public boolean onNavigationItemSelected(MenuItem menuItem)
{
selectDrawerItem(menuItem);
return true;
}
});
}
Related
I am very new to android development and hence, I am not able to solve my problems via help from other internet resources. Using Youtube videos, I am designing an app that uses both NavigationDrawer and TabLayout, and all the TabLayout items and navigation drawer items use fragments. My problem is that when I clicked on items in navigation drawers, the app still displays TabLayout's fragments instead of displaying the fragment corresponding to the clicked item from `NavigationDrawer. Please help me with this. I have included code and even an image below. Thanks a lot.
The abovementioned image.
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
private DrawerLayout drawer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//following gives toolbar and navigation bar can be viewed by sliding L-R
Toolbar toolbar = findViewById(R.id.toolbar_main);
setSupportActionBar(toolbar);
//attach sectionpageadapter to viewpager
SectionPagerAdapter pagerAdapter = new SectionPagerAdapter(getSupportFragmentManager());
ViewPager pager = findViewById(R.id.pager);
pager.setAdapter(pagerAdapter);
//attach viewpager to tablayout
TabLayout tabLayout = findViewById(R.id.tabs);
tabLayout.setupWithViewPager(pager);
//following to give hamburger sign to navigation drawer
drawer = findViewById(R.id.drawer_layout);
//references to listen to click events on navigation views
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
//following for hamburger sign to rotate when slide from L-R
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer,toolbar,
R.string.navigation_drawer_open,R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
//below is our default fragment which will be shown on create, without any clicks
//if statement so that it wont reload on rotation or resume of the device
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new HomeFragment()).commit();
navigationView.setCheckedItem(R.id.nav_home);
}
}
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
switch (menuItem.getItemId()){
case R.id.nav_home:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new HomeFragment()).commit();
break;
case R.id.nav_myaccount:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new AccountFragment()).commit();
break;
case R.id.nav_mymessages:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new MessageFragment()).commit();
break;
case R.id.nav_mysongs:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new MySongFragment()).commit();
break;
case R.id.nav_mystores:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new StoreFragment()).commit();
break;
}
drawer.closeDrawer(GravityCompat.START);
return true;
}
#Override
//following for closing navagation bar instead of leaving activity immediately when you press back button
public void onBackPressed() {
if(drawer.isDrawerOpen(GravityCompat.START)){
drawer.closeDrawer(GravityCompat.START);
}else {
super.onBackPressed();
}
}
private class SectionPagerAdapter extends FragmentPagerAdapter{
public SectionPagerAdapter(FragmentManager fm){
super(fm,BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
#Override
public int getCount() {
return 4;
}
#NonNull
#Override
public Fragment getItem(int position) {
switch (position){
case 0:
return new HomeFragment();
case 1:
return new FragmentArtists();
case 2:
return new FragmentAlbum();
case 3:
return new FragmentPlaylists();
}
return null;
}
#Nullable
#Override
public CharSequence getPageTitle(int position) {
switch (position){
case 0:
return getResources().getText(R.string.home_tab);
case 1:
return getResources().getText(R.string.artist_tab);
case 2:
return getResources().getText(R.string.album_tab);
case 3:
return getResources().getText(R.string.playlist_tab);
}
return null;
}
}
}
Replace this code!
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
switch (menuItem.getItemId()){
case R.id.nav_home:
pager.setVisibility(View.VISIBLE);
tabs.setVisibility(View.VISIBLE);
fragmentConterner.setVisibility(View.GONE);
break;
case R.id.nav_myaccount:
pager.setVisibility(View.GONE);
tabs.setVisibility(View.GONE);
fragmentConterner.setVisibility(View.VISIBLE);
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new AccountFragment()).commit();
break;
case R.id.nav_mymessages:
pager.setVisibility(View.GONE);
tabs.setVisibility(View.GONE);
fragmentConterner.setVisibility(View.VISIBLE);
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new MessageFragment()).commit();
break;
case R.id.nav_mysongs:
pager.setVisibility(View.GONE);
tabs.setVisibility(View.GONE);
fragmentConterner.setVisibility(View.VISIBLE);
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new MySongFragment()).commit();
break;
case R.id.nav_mystores:
pager.setVisibility(View.GONE);
tabs.setVisibility(View.GONE);
fragmentConterner.setVisibility(View.VISIBLE);
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new StoreFragment()).commit();
break;
}
drawer.closeDrawer(GravityCompat.START);
return true;
}
I hope it's helpful for you!
you have the provision to set the visibility of the layout elements to visible,invisible and gone. Programatically you can do this by
ViewPager.setVisibility(View.GONE);
TabLayout.setVisibility(View.GONE);
and also you can show the FrameLayout that you are using to inflate the FrameLayout container.
FrameLayout.setVisibility(View.VISIBLE);
And start with having the FrameLayout set to gone in the XML attribute.
android:visibility="gone"
I hope it helps.
I have the following bottom navbar code to switch between 3 fragments:
public class MainActivity extends AppCompatActivity {
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.navigation_home:
fragment = new HomeFragment();
break;
case R.id.navigation_dashboard:
fragment = new DashboardFragment();
break;
case R.id.navigation_notifications:
fragment = new NotificationsFragment();
break;
}
return loadFragment(fragment);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadFragment(new HomeFragment());
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}
private boolean loadFragment(Fragment fragment) {
//switching fragment
if (fragment != null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, fragment)
.commit();
return true;
}
return false;
}
}
In the fragments there are RecyclerViews with lists. Every time I switch between the tabs (between fragments), it looks like the fragment is reloaded, and the lists jump to the top. I want to prevent that reloading so that the user stays on the same place in the list he viewed before switching fragments
The problem is that you are creating a new instance every time. You can cache the instance like:
private Fragment mHomeFragment = new HomeFragment();
private Fragment mDashboardFragment = new DashboardFragment();
private Fragment mNotificationsFragment = new NotificationsFragment();
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.navigation_home:
fragment = mHomeFragment;
break;
case R.id.navigation_dashboard:
fragment = mDashboardFragment;
break;
case R.id.navigation_notifications:
fragment = mNotificationsFragment;
break;
}
return loadFragment(fragment);
}
As we could see, you are always replace your fragment when clicks on bottom navigation, replace means previous fragment removes and state cleans. The solution is do not create your fragment each time and use attach/detach method for showing actual fragment. Here is already described about these methods.
I'm not an expert in Android, but really interested in fragments. Would be grateful for your help!
I've implemented a navigation drawer in my app. There is a base drawer activity and a number of fragments a user can switch between from the drawer menu. There is no problem if I want to move to another fragment, but it is working when I use an intent to start a new activity. If you look at my code below you'll see that I use two separate menus: one is for ActionBar icons (cart and search), where intents work perfectly and another one is for Nav drawer to jump between fragments. Is there any way to combine it in one? Basically, I need to move to Profile and Log out activities from nav drawer. Thank you for your advice in advance!
The screen is here
Java file
public class BaseDrawerActivity extends AppCompatActivity {
private DrawerLayout drawerLayout;
private NavigationView nvDrawer;
private ActionBarDrawerToggle actionBarDrawerToggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base_drawer);
drawerLayout = findViewById(R.id.drawer);
actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.open, R.string.close);
drawerLayout.addDrawerListener(actionBarDrawerToggle);
actionBarDrawerToggle.syncState();
nvDrawer = findViewById(R.id.nvgView);
// Setup drawer view
setupDrawerContent(nvDrawer);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//Menu created for cart and search icons
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main_menu, menu);
return super.onCreateOptionsMenu(menu);
//return true;
}
//This method is designed only for cart and search icons
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(actionBarDrawerToggle.onOptionsItemSelected(item)){
return true;
} else if (id == R.id.cart) {
Intent intent = new Intent(getApplicationContext(), CartActivity.class);
startActivity(intent);
} else if (id == R.id.search) {
Intent intent = new Intent(getApplicationContext(), SearchActivity.class);
startActivity(intent);
}
return super.onOptionsItemSelected(item);
}
//This method is to set up the drawer content/menu
private void setupDrawerContent(NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
selectDrawerItem(menuItem);
return true;
}
});
}
public void selectDrawerItem(MenuItem menuItem) {
// Here we create a new fragment and specify the fragment to show based on nav item clicked
Fragment fragment = null;
Class fragmentClass;
switch(menuItem.getItemId()) {
case R.id.nav_home:
fragmentClass = HomeFragment.class;
break;
case R.id.nav_cat:
fragmentClass = CatalogFragment.class;
break;
case R.id.nav_logout:
fragmentClass = CatalogFragment.class;
break;
case R.id.nav_login:
//what should I add here to be able to move to another activity (not a fragment). It doesn't work when I use intents
case R.id.nav_profile:
//need to move to another activity
default:
fragmentClass = HomeFragment.class;
}
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.flcontent, fragment).addToBackStack("back tag").commit();
// Highlight the selected item has been done by NavigationView
menuItem.setChecked(true);
// Set action bar title
setTitle(menuItem.getTitle());
// Close the navigation drawer
drawerLayout.closeDrawers();
}
}
Have you tried doing the same thing you did with the optionItems and preventing the code related to the fragment to be executed when starting an Activity:
public class BaseDrawerActivity extends AppCompatActivity {
private DrawerLayout drawerLayout;
private NavigationView nvDrawer;
private ActionBarDrawerToggle actionBarDrawerToggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base_drawer);
drawerLayout = findViewById(R.id.drawer);
actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.open, R.string.close);
drawerLayout.addDrawerListener(actionBarDrawerToggle);
actionBarDrawerToggle.syncState();
nvDrawer = findViewById(R.id.nvgView);
// Setup drawer view
setupDrawerContent(nvDrawer);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//Menu created for cart and search icons
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main_menu, menu);
return super.onCreateOptionsMenu(menu);
//return true;
}
//This method is design only for cart and search icons
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(actionBarDrawerToggle.onOptionsItemSelected(item)){
return true;
} else if (id == R.id.cart) {
Intent intent = new Intent(getApplicationContext(), CartActivity.class);
startActivity(intent);
} else if (id == R.id.search) {
Intent intent = new Intent(getApplicationContext(), SearchActivity.class);
startActivity(intent);
}
return super.onOptionsItemSelected(item);
}
//This method is to set up the drawer content/menu
private void setupDrawerContent(NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
selectDrawerItem(menuItem);
return true;
}
});
}
public void selectDrawerItem(MenuItem menuItem) {
// Here we create a new fragment and specify the fragment to show based on nav item clicked
Fragment fragment = null;
Class fragmentClass;
switch(menuItem.getItemId()) {
case R.id.nav_home:
fragmentClass = HomeFragment.class;
break;
case R.id.nav_cat:
fragmentClass = CatalogFragment.class;
break;
case R.id.nav_logout:
fragmentClass = CatalogFragment.class;
break;
case R.id.nav_login:
Intent intent = new Intent(getApplicationContext(), OtherActivity.class);
startActivity(intent);
break;
case R.id.nav_profile:
Intent intent = new Intent(getApplicationContext(), ProfileActivity.class);
startActivity(intent);
break;
default:
fragmentClass = HomeFragment.class;
}
//Code related to fragment should not execute when choosing to start an Activity
if(fragmentClass != null){
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.flcontent, fragment).addToBackStack("back tag").commit();
// Highlight the selected item has been done by NavigationView
}
menuItem.setChecked(true);
// Set action bar title
setTitle(menuItem.getTitle());
// Close the navigation drawer
drawerLayout.closeDrawers();
}
}
I have a navigation drawer but the main activity has nothing, only the main page fragment has some thing, I want this fragment to be called every time the application opens. Anyone have any idea how to do this?
here is an example
As in code below, add this line in your code onNavigationItemSelected(nvDrawer.getMenu().getItem(0));
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
// ...From section above...
// Find our drawer view
nvDrawer = (NavigationView) findViewById(R.id.nvView);
// Setup drawer view
setupDrawerContent(nvDrawer);
selectDrawerItem(nvDrawer.getMenu().getItem(0));
}
private void setupDrawerContent(NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
selectDrawerItem(menuItem);
return true;
}
});
}
public void selectDrawerItem(MenuItem menuItem) {
// Create a new fragment and specify the fragment to show based on nav item clicked
Fragment fragment = null;
Class fragmentClass;
switch(menuItem.getItemId()) {
case R.id.nav_first_fragment:
fragmentClass = FirstFragment.class;
break;
case R.id.nav_second_fragment:
fragmentClass = SecondFragment.class;
break;
case R.id.nav_third_fragment:
fragmentClass = ThirdFragment.class;
break;
default:
fragmentClass = FirstFragment.class;
}
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.flContent, fragment).commit();
// Highlight the selected item has been done by NavigationView
menuItem.setChecked(true);
// Set action bar title
setTitle(menuItem.getTitle());
// Close the navigation drawer
mDrawer.closeDrawers();
}
}
Problem:
Each time the BottomNavigationView is clicked the fragment is re-created.
Currently in each fragment I have Recycler View that runs only once when creating the Fragment.
In this case, the RecyclerView data is loaded every time. And that's not what I'd like.
How could I work so that the Fragment remains active after it is clicked the first time. And when you go back to the Fragment already created, just display it without recreating it every time?
My attempts:
BottomNavigationView bottomNavigationView =(BottomNavigationView) findViewById(R.id.bottomNavView_Bar);
BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);
final Menu menu = bottomNavigationView.getMenu();
fragmentManager = getSupportFragmentManager();
final FragmentTransaction transaction = fragmentManager.beginTransaction();
/* Fragmento Start */
transaction.replace(R.id.content_home, new MainFragment()).commit();
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Intent in;
Fragment fragment = null;
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.content_home);
switch (item.getItemId()){
case R.id.ic_home:
if (!(currentFragment instanceof MainFragment)) {
fragment = new MainFragment();
toolbar.setTitle("Main");
item = menu.getItem(0);
item.setChecked(true);
}
break;
case R.id.ic_categorias:
if (!(currentFragment instanceof CategoriasFragment)) {
fragment = new CategoriasFragment();
toolbar.setTitle("Categorias");
item = menu.getItem(1);
item.setChecked(true);
}
break;
case R.id.ic_calendar:
if (!(currentFragment instanceof FeedUserFragment)) {
fragment = new FeedUserFragment();
item = menu.getItem(2);
toolbar.setTitle("Feed");
item.setChecked(true);
}
break;
case R.id.ic_explore:
if (!(currentFragment instanceof ExploreFragment)) {
fragment = new ExploreFragment();
item = menu.getItem(3);
toolbar.setTitle("Explorar");
item.setChecked(true);
}
break;
case R.id.ic_person:
if (!(currentFragment instanceof Opcoes)) {
fragment = new Opcoes();
toolbar.setTitle("Opções");
item = menu.getItem(4);
item.setChecked(true);
}
break;
}
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.content_home, fragment);
transaction.commit();
return false;
}
});
You are replacing your fragment every time ie after your switch block
complete.
Solution: Replace only when condition meets and use addToBackStack which helps to maintain stacks. You can read more about from this site
Try this,
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Intent in;
Fragment fragment = null;
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.content_home);
switch (item.getItemId()){
case R.id.ic_home:
if (!(currentFragment instanceof MainFragment)) {
fragment = new MainFragment();
toolbar.setTitle("Main");
item = menu.getItem(0);
item.setChecked(true);
loadFragment(fragment,"mainMenu");
}
break;
case R.id.ic_categorias:
if (!(currentFragment instanceof CategoriasFragment)) {
fragment = new CategoriasFragment();
toolbar.setTitle("Categorias");
item = menu.getItem(1);
item.setChecked(true);
loadFragment(fragment,"categories");
}
break;
case R.id.ic_calendar:
if (!(currentFragment instanceof FeedUserFragment)) {
fragment = new FeedUserFragment();
item = menu.getItem(2);
toolbar.setTitle("Feed");
item.setChecked(true);
loadFragment(fragment,"feedUsers");
}
break;
case R.id.ic_explore:
if (!(currentFragment instanceof ExploreFragment)) {
fragment = new ExploreFragment();
item = menu.getItem(3);
toolbar.setTitle("Explorar");
item.setChecked(true);
loadFragment(fragment,"explore");
}
break;
case R.id.ic_person:
if (!(currentFragment instanceof Opcoes)) {
fragment = new Opcoes();
toolbar.setTitle("Opções");
item = menu.getItem(4);
item.setChecked(true);
loadFragment(fragment,"opcoes");
}
break;
}
return false;
}
});
/**
* Create new method which replace your old fragment
*/
public void loadFragment(Fragment fragment, String tag){
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.content_home, fragment);
transaction.addToBackStack(tag);
transaction.commit();
}
I would try transaction.add() and search for fragments in back stack with this method findFragmentByTag. https://developer.android.com/reference/android/support/v4/app/FragmentManager.html#findFragmentByTag(java.lang.String).