I have 3 fragments, Home, Menu and orders they can be loaded by bottomnavigtioview items and the title shown by it as well
once navigate from Home to Orders then if you want to go back to Home From Orders the title still "Orders"
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment;
switch (item.getItemId()) {
case R.id.navigation_home:
toolbar.setTitle(getResources().getString(R.string.title_home));
fragment = new HomeFragment();
loadFragment(fragment);
return true;
case R.id.navigation_menu:
toolbar.setTitle(getResources().getString(R.string.fragment_title_menu));
fragment = new ProductFragment();
loadFragment(fragment);
return true;
case R.id.navigation_orders:
toolbar.setTitle(getResources().getString(R.string.title_orders));
fragment = new OrdersFragment();
loadFragment(fragment);
return true;
}
return false;
}
};
private void loadFragment(Fragment fragment) {
// load fragment
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
navigation = findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
// attaching bottom sheet behaviour - hide / show on scroll
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) navigation.getLayoutParams();
layoutParams.setBehavior(new BottomNavigationBehavior());
toolbar.setTitle(getResources().getString(R.string.title_home));
Fragment f = HomeFragment.newInstance();
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_container, f)
.commit();
}`
I have Also Tried this but its not working
`
fragmentmanger.addOnBackStackChangedListener -> public void onBackStackChanged() {
}`
Instead of calling toolbar.setTitle in your onNavigationItemSelected method, move it to onCreateView of each fragment. When you navigate back to a Fragment, onCreateView is executed again.
It worked for me when calling it in onResume like this in each fragment:
if(getActivity()!=null) {
((MainActivity)getActivity()).setActionBarTitle
(context.getResources().getString(R.string.YOUR_TITLE));
this is the function setActionBarTitle in MainActivity
public void setActionBarTitle(String title) {
toolbar.setTitle(title);
}
Related
I have a bottom nav bar with 4 section fragment attached. In every fragment there is something by clicking that I am going to other fragment which are not section fragment. I want to show bottom nav bar only in section fragment. So how to hide bottom nav bar in other fragment?Here is my bottom nav bar code:
package com.fahim69.bazaarapp.FragmentHolder;
public class ShowFragment extends AppCompatActivity {
BottomNavigationView bottomnav;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_fragment);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
bottomnav = findViewById(R.id.nav_bar);
replacefragment(new HomeFragment());
bottomnav.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.nav_home:
replacefragment(new HomeFragment());
break;
case R.id.nav_category:
replacefragment(new CategoryFragment());
break;
case R.id.nav_cart:
replacefragment(new CartFragment());
break;
case R.id.nav_profile:
replacefragment(new ProfileFragment());
break;
}
return true;
}
});
}
private void replacefragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
//fragmentManager.popBackStack();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
#Override
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
if(fm.getBackStackEntryCount()>0)fm.popBackStack();
else{
super.onBackPressed();
}
}
}
Look at this code of replace fragment :
fragmentTransaction.replace(R.id.fragment_container, fragment);
We are loading all the fragment on "R.id.fragment_container" frame of the "R.layout.activity_show_fragment" layout . In the show_fragment layout , there exist a nav_bar , due to which all of the fragment are being shown with bottom navigation.
In order to hide bottom navigation in other fragment than sectionfragment, create a new activity without bottom_navigation and replace the fragment in new fragment_container of that activity.
Hello im trying to navigate between some fragments with addToBaackStack but having issues with it ,
Ok i will explain it in detail so there should be no confusuion
1 :- I have only one activity (main activity) which consist of all the other fragments and a fragment container to hold the fragments in it , i have implemented bottom navigation in the main activity ,where the bottom navigation have 5 main fragments home,following,upload,notification and profile my issues is related to the profile fragment
2 :- In the profile fragment i have some buttons like edit profile button which opens edit profile fragment but now when i presse back it should navigate back to the profile fragment which it is not doing ,its is navigating to the last fragment of the bottomnavigation (which can be any other of the main fragments for eg if my last fragment is following fragment then when i press back from the edit profile fragment it goes to the following fragment )but this not happens if i put a back arrow icon in edit profile fragment then when i click the back arrow it perfectly navigate me to the profile fragments as it is not related to addToBackStack
It shows that the issue is related with my bottom navigation but i dont know how to exactly fix it
Prifile_Fragment.java
editProfileButton.setOnClickListener(v -> {
Fragment edit_profile = new Edit_Profile();
assert getFragmentManager() != null;
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, edit_profile);
transaction.addToBackStack(null);
transaction.commit();
});
MainActivity.java // where the bottom navigation is implemented
public class MainActivity extends AppCompatActivity {
public BottomNavigationView bottomNavigationView;
Deque<Integer> integerDeque = new ArrayDeque<>(4);
boolean flag = true;
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
setContentView(R.layout.activity_main);
Window window = this.getWindow();
window.setStatusBarColor(this.getResources().getColor(R.color.black));
bottomNavigationView = findViewById(R.id.bottom_navigation_view);
integerDeque.push(R.id.nav_home);
loadFragments(new Home_Fragment());
bottomNavigationView.setSelectedItemId(R.id.nav_home);
bottomNavigationView.setOnNavigationItemSelectedListener(
item -> {
int id = item.getItemId();
if (integerDeque.contains(id)) {
if (id == R.id.nav_home) {
integerDeque.size();
if (flag) {
integerDeque.addFirst(R.id.nav_home);
flag = false;
}
}
integerDeque.remove(id);
}
integerDeque.push(id);
loadFragments(getFragment(item.getItemId()));
return false;
}
);
}
#SuppressLint("NonConstantResourceId")
private Fragment getFragment(int itemId) {
switch (itemId) {
case R.id.nav_home:
bottomNavigationView.getMenu().getItem(0).setChecked(true);
return new Home_Fragment();
case R.id.nav_following:
bottomNavigationView.getMenu().getItem(1).setChecked(true);
return new Following_Fragment();
case R.id.nav_upload:
bottomNavigationView.getMenu().getItem(2).setChecked(true);
return new Upload_Fragment();
case R.id.nav_notification:
bottomNavigationView.getMenu().getItem(3).setChecked(true);
return new Notification_Fragment();
case R.id.nav_profile:
bottomNavigationView.getMenu().getItem(4).setChecked(true);
return new Profile_Fragment();
}
bottomNavigationView.getMenu().getItem(0).setChecked(true);
return new Home_Fragment();
}
public void loadFragments(Fragment fragment) {
if (fragment != null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment, fragment.getClass().getSimpleName())
.commit();
}
}
#Override
public void onBackPressed() {
integerDeque.pop();
if (!integerDeque.isEmpty()) {
loadFragments(getFragment(integerDeque.peek()));
} else {
finish();
}
}
}
Have you consider to use popBackStack ? You can try this.
#Override
public void onBackPressed() {
final FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack();
} else {
finish();
}
}
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 have a bottom navigation bar that contains 4 fragments and when a tab is selected a new instance of that fragment is loaded.
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 = HomeFragment.newInstance();
break;
case R.id.navigation_cards:
fragment = CardsFragment.newInstance();
break;
case R.id.navigation_deals:
fragment = DealsFragment.newInstance();
break;
case R.id.navigation_settings:
fragment = SettingsFragment.newInstance();
break;
}
if (fragment != null) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.content, fragment);
fragmentTransaction.commit();
}
return true;
}
};
Now in my HomeFragment there is a RecyclerView that On Item Select it opens a new Fragment:
myViewHolder.cardView.setOnClickListener(view -> {
System.out.println("clicked");
Fragment fragment = new TargetDetailsFragment();
FragmentTransaction ft = ((AppCompatActivity) context).getSupportFragmentManager()
.beginTransaction();
ft.replace(R.id.content, fragment).addToBackStack(null);
ft.commit();
});
I want to add a back button to the TargetDetails Fragments that takes you back to the home page when selected and I attempted doing that by implementing OnBackStackChangedListener in the Main activity
#Override
public void onBackStackChanged() {
shouldDisplayHomeUp();
}
public void shouldDisplayHomeUp(){
//Enable Up button only if there are entries in the back stack
boolean canback = getSupportFragmentManager().getBackStackEntryCount()>0;
getSupportActionBar().setDisplayHomeAsUpEnabled(canback);
}
#Override
public boolean onSupportNavigateUp() {
//This method is called when the up button is pressed. Just the pop back stack.
getSupportFragmentManager().popBackStack();
return true;
}
}
but the problem is when I click on it its reloads the HomeFragment Again but I simply want it to go back to the saved instance of that Fragment
Here is my code that I have used for the ViewPager, the idea is to see if the current page number is 0 than to proceed super.onBackPressed(); otherwise go to the previous fragment:
#Override
public void onBackPressed() {
if(vpPager.getCurrentItem()!=0) {
vpPager.setCurrentItem(vpPager.getCurrentItem()-1, true);
} else {
super.onBackPressed();
}
}
By adding below code in your Activity.
The fragment back stack can be managed.
#Override
public void onBackPressed() {
int count = getFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
//additional code
} else {
getFragmentManager().popBackStack();
}
}
Hello #Bolu Okunaiya i think you should try this it will help you to manage backstack to desired fragment without loading same fragment again.
For Stop loading previous fragment you should use "add" instead of "replace" with your FragmentTransaction
Inside your MainActivity
#Override
public void onBackStackChanged() {
//shouldDisplayHomeUp();
Fragment currentFragment = getActivity().getFragmentManager()
.findFragmentById(R.id.fragment_container);
if (currentFragment instanceof TargetDetails) {
Log.v(TAG, "your current fragment is TargetDetails");
popBackStackImmediate(); //<<<< immediate parent fragment will open,which is your HomeFragement
}
}
To use popBackStackImmediate() you need to *replace FragmentA with FragmentB and use addToBackstack() before commit().
I have a navigation view with some items in it, and when one item is pressed it will go to that fragment. For example, if you press the "Home" item, on the drawer, it will bring up the home fragment.
navigationView = (NavigationView)findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.home_id:
HomeFragment homeFragment = (HomeFragment) fragmentManager.findFragmentByTag("Home");
if (homeFragment == null)
homeFragment = new HomeFragment();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.Main, homeFragment, "Home");
fragmentTransaction.commit();
getSupportActionBar().setTitle("Home");
item.setChecked(true);
drawerLayout.closeDrawers();
break;
case R.id.chat_id:
ChatFragment chatFragment = (ChatFragment) fragmentManager.findFragmentByTag("Chat");
if (chatFragment == null)
chatFragment = new ChatFragment();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.Main, chatFragment, "Chat");
fragmentTransaction.commit();
getSupportActionBar().setTitle("Chat");
item.setChecked(true);
drawerLayout.closeDrawers();
break;
}
}
}
So what I think is happening is that when I am using the replace() method, it is destroying the chat fragment. What if I have data on the chat fragment, and I want to make sure the data does not go away when I change fragments.
In the ChatFragment class I have put this override method:
#Override
public void onSaveInstanceState(Bundle outState)
{
Log.d("CHATFRAG", "onSaveInstanceState: been called ");
super.onSaveInstanceState(outState);
outState.putString("textView",textView.getText().toString());
//Save the fragment's state here
}
Now when I switch between fragments in my app, this method does not get called, which means the fragment is being destroyed.
Is there an alternative way where I can swap the current fragment that is on screen, with the desired fragment(without destroying both)?
I will be having more fragments (up to ten), is there an optimised solution that will not require duplicate code?
you are replacing fragment with other, so first one will get distroyed. If you dont want it to destroy you need to add it instead of replace
fragmentTransaction.add(R.id.Main, homeFragment, "Home");
You can create your fragments in advance, for instance in your activity's onCreate() method:
private HomeFragment homeFragment;
private ChatFragment chatFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
homeFragment = new HomeFragment();
chatFragment = new ChatFragment();
}
Then in your navigation code:
#Override
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.home_id:
if (homeFragment == null)
homeFragment = new HomeFragment();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.Main, homeFragment, "Home");
fragmentTransaction.commit();
getSupportActionBar().setTitle("Home");
item.setChecked(true);
drawerLayout.closeDrawers();
break;
case R.id.chat_id:
if (chatFragment == null)
chatFragment = new ChatFragment();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.Main, chatFragment, "Chat");
fragmentTransaction.commit();
getSupportActionBar().setTitle("Chat");
item.setChecked(true);
drawerLayout.closeDrawers();
break;
}
}
Although I think Ravi Rupareliya's answer is the best choice (using .add), I'll share another way I think might work.
You can add two FrameLayout on top of each other, .add a Fragment into both, and then alternate their visibility.