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.
Related
I have bottomNavigationView with 3 menus. Middle item is selected by default when app starts.
Middle fragment contains a recycler view which fetches data from sharesPreferences.
But when I select different menu and again select middle menu(middle fragment), the recylerview from middle fragment just disappers...
Anyone know what could be the reason?
Created fragments
homeFragment = new HomeFragment(); //(middle fragment contains recycler view)
appSettingFragment = new AppSettingFragment();
infoFragment = new InfoFragment();
Changing fragments
//this method is used for changing first and last fragment
bottomNavigation.setOnNavigationItemSelectedListener(item -> {
switch (item.getItemId()) {
case R.id.settings:
btnAdd.setImageResource(R.drawable.ic_baseline_home_24);
addvis = false;
openFragment(appSettingFragment);
return true;
case R.id.info:
btnAdd.setImageResource(R.drawable.ic_baseline_home_24);
addvis = false;
openFragment(infoFragment);
return true;
}
return true;
});
// this is used for middle fragment
btnAdd.setOnClickListener(v -> {
if (addvis) {
startCreateFormActivity("Untitled Form");
} else {
addvis = true;
btnAdd.setImageResource(R.drawable.ic_baseline_add_24);
bottomNavigation.setSelectedItemId(R.id.home);
//homeFragment = new HomeFragment();
openFragment(homeFragment);
}
});
}
public void openFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container, fragment);
transaction.commit();
}
I have created an app with a bottom navigation fragment which consists of 5 main fragments and one extra sub fragment (login Fragment). the thing is I want this login fragment to be replaced with the userAccount fragment once user has logged in successfully.
Note: I am running the App statically at first so I am using a variable Boolean Called Status to check whether user has logged in or not
private static final boolean Status = false;
final Fragment f1 = new HomeFragment();
final Fragment f2 = new SearchFragment();
final Fragment f3 = new CameraFragment();
final Fragment f4 = new ChatFragment();
final Fragment f5 = new AccountFragment();
// logginFragment page should be replaced with AccountFragment once user logged in successfully
final Fragment f6 = new logginFragment();
private BottomNavigationViewEx.OnNavigationItemSelectedListener navListener =
new BottomNavigationViewEx.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.nav_home:
fm.beginTransaction().hide(active).show(f1).commit();
active = f1;
return true;
case R.id.nav_search:
fm.beginTransaction().hide(active).show(f2).commit();
active = f2;
return true;
case R.id.nav_camera:
fm.beginTransaction().hide(active).show(f3).commit();
active = f3;
return true;
case R.id.nav_chat:
fm.beginTransaction().hide(active).show(f4).commit();
active = f4;
return true;
case R.id.nav_account:
fm.beginTransaction().hide(active).show(f5).commit();
active = f5;
return true;
}
/* \getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
selectedFragment).commit();*/
return false;
}
};
Your Code changes the fragment only when one of the Bottom Navigation Bar item is selected. You can replace the login fragment with account fragment when the login is successful(i.e when button is tapped) and set it to active rather than listening for the change in selection. Let me know if this helps.
void login()
{
if(Successful)
{
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_login,R.id.fragment_account)
.commit();
}
}
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.
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.
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?