Prevent fragment refreshing with bottom navbar - android

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.

Related

How to give Backward Slide Animation to Fragments with Bottom Navigation Bar in Android

I have a Bottom Navigation Bar Activity with changing fragments. i have done forward slide animation on fragments using 'setCustomAnimations' function but i want backward slide animations it has the same animation as for forward animation. i am unable to solve it, i have also tried many different solutions but none of them are working. can anyone help me give a solution to this
Here is the Code
public class Homepage extends AppCompatActivity {
private BottomNavigationView mainNav;
private FrameLayout mainFrame;
private HomeFragment homeFragment;
private GamesFragment gamesFragment;
private ExerciseFragment exerciseFragment;
private GalleryFragment galleryFragment;
private MoreFragment moreFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_homepage);
mainNav = (BottomNavigationView) findViewById(R.id.main_nav);
mainFrame = (FrameLayout) findViewById(R.id.main_frame);
homeFragment = new HomeFragment();
gamesFragment = new GamesFragment();
exerciseFragment = new ExerciseFragment();
galleryFragment = new GalleryFragment();
moreFragment = new MoreFragment();
setFragment(homeFragment);
mainNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.nav_home:
setFragment(homeFragment);
return true;
case R.id.nav_games:
setFragment(gamesFragment);
return true;
case R.id.nav_exercise:
setFragment(exerciseFragment);
return true;
case R.id.nav_gallery:
setFragment(galleryFragment);
return true;
case R.id.nav_more:
setFragment(moreFragment);
return true;
default:
return false;
}
}
});
}
private void setFragment(Fragment fragment){
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.slide_in_right,R.anim.slide_out_left);
fragmentTransaction.replace(R.id.main_frame, fragment);
fragmentTransaction.commit();
}
}

Android Navigation Bottom Fragments overlapping

I am using a navigation bottom with 4 items in my app, so I have 4 fragments.
the first fragment(home page) contains a recyclerView and other fragments don't contain any recyclerView.
The problem is here;
when I navigate to other fragments I can see the recycler view in the background.
and when I navigatie back to the first fragment there is another recycler view under the original one!
I have used this :
fm.beginTransaction().hide(active).show(fragment2).commit();
but the hide() method doesn't work.
Here is the related parts of my code:
I have globally defined these
final Fragment fragment1 = new HomeFragment();
final Fragment fragment2 = new AddFragment();
final Fragment fragment3 = new CalendarFragment();
final Fragment fragment4 = new ProfileFragment();
final FragmentManager fm = getSupportFragmentManager();
Fragment active = fragment1;
then
In the onCreate :
fm.beginTransaction().add(R.id.nav_host_fragment, fragment4, "4").hide(fragment4).commit();
fm.beginTransaction().add(R.id.nav_host_fragment, fragment3, "3").hide(fragment3).commit();
fm.beginTransaction().add(R.id.nav_host_fragment, fragment2, "2").hide(fragment2).commit();
fm.beginTransaction().add(R.id.nav_host_fragment, fragment1, "1").commit();
and at last
the navigation item listener :
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
if (active == fragment1)
return false;
fm.beginTransaction().hide(active).show(fragment1).commit();
active = fragment1;
return true;
case R.id.navigation_add:
if (active == fragment2)
return false;
fm.beginTransaction().hide(active).show(fragment2).commit();
active = fragment2;
return true;
case R.id.navigation_calendar:
if (active == fragment3)
return false;
fm.beginTransaction().hide(active).show(fragment3).commit();
active = fragment3;
return true;
case R.id.navigation_profile:
if (active == fragment4)
return false;
fm.beginTransaction().hide(active).show(fragment4).commit();
active = fragment4;
return true;
}
return false;
}
};
I have used navGraph in my fragment in the XML file previously and I've forgotten to delete the navGraph, so it was showing the first fragment in the navGraph in the background.

How to change the title of fragment when press back?

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);
}

Android - PageView in new BottomNavigationBar - prevent reload fragments

In my StartActivity the BottomNavigationBar Listener has the following setup:
private GuideFragment guideFragment = new GuideFragment();
private MapFragment mapFragment = new MapFragment();
private MoreFragment moreFragment = new MoreFragment();
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()) {
case R.id.navigation_guide:
selectedFragment = guideFragment;
break;
case R.id.navigation_map:
selectedFragment = mapFragment;
break;
case R.id.navigation_more:
selectedFragment = moreFragment;
break;
}
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.content, selectedFragment);
transaction.commit();
return true;
}
};
As I mentioned above I want to prevent that the selected fragments always reloads the sources/view.
I tried out some stuff like - in the fragments:
if (rootView == null)
inflater.inflate...
But the fragments still recreate the view and load (in my case) webresources new.
I read something that a PageView could help, especially
offScreenPageLimit
should do the magic.
My main question is where should I implement a PageViewer - Is it possible in my StartActivity?
Or can I solve the problem in an other way?
I did it boys!
There is no ViewPager necessary.
Here is my solution (all coded in StartActivity not in Fragments):
private final GuideFragment guideFragment = new GuideFragment();
private final MapFragment mapFragment = new MapFragment();
private final MoreFragment moreFragment = new MoreFragment();
private final android.app.FragmentManager fm = getFragmentManager();
Fragment active = guideFragment;
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_guide:
if(active != guideFragment) {
fm.beginTransaction().show(guideFragment).commit();
}
else {
fm.beginTransaction().hide(active).show(guideFragment).commit();
}
active = guideFragment;
break;
case R.id.navigation_map:
fm.beginTransaction().hide(active).show(mapFragment).commit();
active = mapFragment;
break;
case R.id.navigation_more:
fm.beginTransaction().hide(active).show(moreFragment).commit();
active = moreFragment;
break;
}
return true;
}
};
and in onCreate list the transaction commits.
fm.beginTransaction().add(R.id.content,moreFragment).commit();
fm.beginTransaction().add(R.id.content, mapFragment).commit();
fm.beginTransaction().add(R.id.content, guideFragment).commit();
It is very important to commit the first tabs fragment last(fragm3,fragm2,fragm1) if you have 3 tabs.
Highly speed performance on the smartphone now by not loading every fragment new/refresh.

Handle back-press inside of Fragments irrespective of navigation route

My app has a navigation drawer with three items linking to three fragments A, B and C
when I click on the back button from any of the Fragments, the app exits.I solved this by declaring these constants in my base activity:
public static boolean IS_FRAGMENT_A = false;
public static boolean IS_FRAGMENT_B = false;
public static boolean IS_FRAGMENT C = false;
and then in the selectView method I did this:
private void displayView(int position) {
IS_FRAGMENT_A = false;
IS_FRAGMENT_B = false;
IS_FRAGMENT_C = false;
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = new FragmentA();
IS_FRAGMENT_A = true;
break;
case 1:
fragment = new FragmentB();
IS_FRAGMENT_B = true;
break;
case 2:
fragment = new FragmentC();
IS_FRAGMENT_C = true;
break;
default:
break;
}
And in the overriden onBackPressed() method I did this
public void onBackPressed() {
if (IS_FRAGMENT_A) {
finish();
} else {
displayView(0);
}
}
This works fine when am navigating to these fragments from the navigation drawer.However, when I go to any of the fragments through an ActionBar button, the onBackPressed method does not work.
In Fragment A, I have an ActionBar button that takes me to Fragment B:
public boolean onOptionsItemSelected(MenuItem menuItem) {
int id = menuItem.getItemId();
switch (id) {
case R.id.action_new:
Fragment fragmentB = new FragmentB();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_container, fragmentB);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
return true;
default:
return super.onOptionsItemSelected(menuItem);
}
}
When I press the back button from FragmentB after navigating to it via this method the app exits, unlike when I navigate to it through the navigation drawer.
I have tried adding this to the onCreate() method of FragmentB with no luck:
BaseActivity.IS_FRAGMENT_B = true;
My question is, how do I make the back button work in all fragments irrespective of how I got there?

Categories

Resources