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().
Related
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 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);
}
I have created a tabbed activity inside a navigation drawer activity. I have linked the lists inside the navigation drawer with individual fragments. I also used the command ft.addToBackStack(null) before ft.commit(). It was perfectly fine and I was able to use it to close the fragments inside the navigation drawer. now I have created webviews inside the fragments of the tabbed activity (home page). I added the onBackPressed to go back inside the webview and now the addToBackStack method stopped working.
For the navigation drawer fragments,
private void dispaySelectedScreen(int id) {
Fragment fragment = null;
switch (id) {
case R.id.fragment1:
fragment = new Fragment1();
break;
case R.id.fragment2:
fragment = new Fragment2();
break;
case R.id.fragment3:
fragment = new Fragment3();
break;
case R.id.fragment4:
fragment = new fragment4();
break;
}
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_main, fragment);
ft.addToBackStack(null);
ft.commit();
}
onBackPressed Method
#Override
public void onBackPressed() {
if (hWebView.canGoBack()) {
hWebView.goBack();
} else if (!getFragmentManager().popBackStackImmediate())
if (sWebView.canGoBack()) {
sWebView.goBack();
} else if (!getFragmentManager().popBackStackImmediate())
if (dWebView.canGoBack()) {
dWebView.goBack();
} else if (!getFragmentManager().popBackStackImmediate());
}
Please help me out!!!
try this code: override onBackPressed() in your tabbed activity (home page).
#Override
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
if (hWebView.canGoBack()) {
hWebView.goBack();
} else if (!getFragmentManager().popBackStackImmediate())
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
} else {
super.onBackPressed();
}
}
App has Viewpager that has four tab with fragment. Second fragment has framelayout "FL" where I put fragment with listview. And when user click listview item opened new fragment with listview in this framelayout "FL" and and so on.
I am going to do catalog with prudacts with multilevel category.
My quation: How can I implement that in second fragment when I opened fragment level 3 than by clicking Toolbar home button go back to fragment level 2 and to another click back to fragment level 1 (popBackStack) and finally when click Toolbar home button go to first Tab. Any help be usefull for me. Thanks
There is what I fecit:
I use home button for go First Tab from other Tabs:
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MainActivity.this.setCurrentItem(0, true);
}
});
To replace fragment use the below code
#Override
public void replaceFragment(Fragment fragment, String title) {
String backStateName = fragment.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
if (!fragmentPopped) { //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.container_body, fragment);
ft.addToBackStack(backStateName);
ft.commit();
// getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setTitle("");
}
}
Add the below mentioned code in your fragment class
Add the below line in your Fragment onCreateView
setHasOptionsMenu(true);
Use the below code to go back the previous fragment.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if (getActivity().getSupportFragmentManager().getBackStackEntryCount() > 1) {
getFragmentManager().popBackStack();
return true;
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public void onDetach() {
super.onDetach();
if (getActivity().getSupportFragmentManager().getBackStackEntryCount() > 1) {
getFragmentManager().popBackStack();
}
}
I am implementing navigation drawer and works well. So i am calling fragment on navigation drawer click and it is also working and further more i am calling another fragment from Home page fragment and maintain the back stack for every fragment but the problem is back press from the child fragment i can't go to Home page fragment and just exited from application. I don't want this. What i want Click on
Navigation Drawer->HomePageFragment->AnotherChild Fragment(On List Item click of HomePageFragment)
but on back pressed without going to Homepage fragment its directly exit with application. Here is my code: (In Fragment Activity with Navigation Drawer)
class SlideitemListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
updateDisplay(position);
}
}
private void updateDisplay(int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new ScheduleFragment();
break;
case 1:
fragment = new Result_Fragment();
break;
case 2:
fragment = new Live_Match_Fragment();
break;
case 3:
// fragment = new Live_Match_Fragment();
break;
case 4:
fragment = new Team_Fragment();
break;
default:
break;
}
if (fragment != null) {
fragmentManager = getFragmentManager();
fragmentManager.popBackStackImmediate("0", 0);
int count = fragmentManager.getBackStackEntryCount();
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
fragmentTransaction.replace(R.id.frame_container, fragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.addToBackStack(String.valueOf(count)).commit();
Log.e("Count in Activiy", ""+count);
// update selected item and title, then close the drawer
setTitle(menutitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
Now in BackPressed() in FragmentActivity.
#Override
public void onBackPressed() {
if (fragmentManager.getBackStackEntryCount() <= 1) {
finish();
return;
}
super.onBackPressed();
}
Now calling another child fragment from HomePage fragment on Listview item click.
team_lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
TeamDetailFragment myDetailFragment = new TeamDetailFragment();
FragmentManager fragmentManager = getFragmentManager();
int count = fragmentManager.getBackStackEntryCount();
Log.e("Count in Fragment", "" + count);
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
fragmentTransaction
.replace(R.id.frame_container, myDetailFragment)
.setTransition(
FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.addToBackStack(String.valueOf(count)).commit();
}
});
So anybody knows then help me. Help will be appreciate.
There is an issue with nested fragments in android
https://code.google.com/p/android/issues/detail?id=40323
Android doesn't handle back press well if transactions were in nested fragments.
To surpass this i am using the following fix inside My Activity
#Override
public void onBackPressed() {
// If the fragment exists and has some back-stack entry
if (myFragment != null && myFragment.getChildFragmentManager().getBackStackEntryCount() > 0) {
// Get the fragment fragment manager - and pop the backstack
myFragment.getChildFragmentManager().popBackStack();
}
// Else, nothing in the direct fragment back stack
else {
// Let super handle the back press
super.onBackPressed();
}
}
I've solved in the following way:
1st solution
#Override
public void onBackPressed() {
FragmentManager fragmentManager = getFragmentManager();
int backCount = fragmentManager.getBackStackEntryCount();
if(backCount > 1) {
super.onBackPressed();
} else {
finish();
}
}
2nd solution
#Override
public void onBackStackChanged() {
FragmentManager fragmentManager = getFragmentManager();
int backCount = fragmentManager.getBackStackEntryCount();
if(backCount == 0) {
finish();
}
}
These allow you to exploit the Android stack when you replace your fragment:
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, yourFragment)
.addToBackStack(null).commit();
When you press back button inside your fragment onBackPressed() method of your activity will be called if you have declared that..So handling back button for fragments within navigation drawer can be one in this way..
MainActvity
public static boolean isMainActivityShown ;
public static boolean isFragment1Shown=false ;
public static boolean isFragment2Shown=false ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
isMainActivityShown=true //inside onCreate method put isMainActivityShown true
.
.
.
{
Fragment currentFragment = new Fragment1();
isMainActivityShown=false; //when moving to fragment1
isFragment1Shown=true;
frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.content_frame, currentFragment)
.commit();
}
.
.
}
#Override
public void onBackPressed() {
if(isMainActivityShown)
{
finish();
}
else if(isFragment1Shown)
{
//write the code to handle back button when you are in Fragment1
}
else if(isFragment2Shown)
{ //When you are in Fragment 2 pressing back button will move to fragment1
Fragment currentFragment = new Fragment1();
isFragment2Shown=false;
isFragment1Shown=true;
FragmentManager frgManager;
frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.content_frame, currentFragment)
.commit();
}
}
Fragment1
Fragment currentFragment = new Fragment2();
MainActivity.isFragment1Shown=false;
MainActivity.isFragment2Shown=true;
frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.content_frame, currentFragment)
.commit();
Now you can replace finish() for fragmentManager.popBackStack(), method of android.support.v4.app.FragmentManager