I am new to Android Developing and I am trying to create an app based on the BottomNavgiationView. One of the bottom navigation Items have an editText so when I switch to another fragment the previous fragment where I wrote something gets overlapped due to replacing.
This is my OnNavigationItemSelectedListener
private void enableNavigation(){
bottomNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch(item.getItemId()){
case R.id.btnHome:
HomeFragment homeFragment = new HomeFragment();
android.support.v4.app.FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.container, homeFragment).commit();
return true;
case R.id.btnChats:
ChatsFragment chatsFragment = new ChatsFragment();
android.support.v4.app.FragmentManager manager1 = getSupportFragmentManager();
manager1.beginTransaction().replace(R.id.container, chatsFragment).commit();
return true;
case R.id.btnPost:
PostsFragment postsFragment = new PostsFragment();
android.support.v4.app.FragmentManager manager2 = getSupportFragmentManager();
manager2.beginTransaction().replace(R.id.container, postsFragment).commit();
return true;
case R.id.btnFavourites:;
FavouritesFragment favouritesFragment = new FavouritesFragment();
android.support.v4.app.FragmentManager manager3 = getSupportFragmentManager();
manager3.beginTransaction().replace(R.id.container, favouritesFragment).commit();
return true;
case R.id.btnProfile:
ProfileFragment profileFragment = new ProfileFragment();
android.support.v4.app.FragmentManager manager4 = getSupportFragmentManager();
manager4.beginTransaction().replace(R.id.container, profileFragment).commit();
return true;
}
return false;
}
});
Anyone having any solution please let me Know..
I assume you meant instance. Each time you switch fragment, you make a new instance and open that. So to stop doing that, you have to keep the first instance built and give that to the fragment manager when you want to switch to it.
For example, let's use your ChatFragment.
Instead of inside the switch statement, you put your ChatsFragment chatsfragmentdeclaration to the top of the Activity, so it's an instance-wide variable. Inside your switch statement, instead of building a new instance every time, you go
case R.id.btnChats:
if(chatsFragment == null) chatsFragment = new ChatsFragment();
android.support.v4.app.FragmentManager manager1 = getSupportFragmentManager();
manager1.beginTransaction().replace(R.id.container, chatsFragment).commit();
return true;
Now you only rebuild your fragment once, when it is first called. From then on, the old instance is reused.
Related
I have an Activity with a BottomNavigationView, which consists of 4 Fragments, the Fragments reload whenever I change tabs, this is my Activity's code
public class MainHomeActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_home);
BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(navigationItemSelectedListener);
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new HomeFragment()).commit();
}
private BottomNavigationView.OnNavigationItemSelectedListener navigationItemSelectedListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull #NotNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()){
case R.id.nav_home:
selectedFragment = new HomeFragment();
break;
case R.id.nav_list:
selectedFragment = new UsersFragment();
break;
case R.id.nav_profile:
selectedFragment = new ProfileFragment();
break;
case R.id.nav_settings:
selectedFragment = new SettingsFragment();
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, selectedFragment).commit();
return true;
}
};
}
In the Fragments im loading data from parse
I know that the mistake im doing is that I'm creating a new instance of the Fragment whenever I switch tabs, but I do not how to fix it or where to start from
I saw some people saying that a ViewPagerAdapter should be used in this case but i cant manage to find a place where its explained properly.
Any assistance would be very appreciated!
Here's an article which describes your case perfectly and in detail.
Basically, it creates a fragment for each tab in memory, and saves them as a local variable in the activity:
final Fragment fragment1 = new HomeFragment();
final Fragment fragment2 = new DashboardFragment();
final Fragment fragment3 = new NotificationsFragment();
final FragmentManager fm = getSupportFragmentManager();
Fragment active = fragment1;
You add all 3 fragments to the manager, but hide 2 of them, so only 1 will be visible:
fm.beginTransaction().add(R.id.main_container, fragment3, "3").hide(fragment3).commit();
fm.beginTransaction().add(R.id.main_container, fragment2, "2").hide(fragment2).commit();
fm.beginTransaction().add(R.id.main_container,fragment1, "1").commit();
You implement the OnNavigationItemSelectedListener of the BottomNavigationView, check which item was pressed, and then show that fragment while hiding the previous:
case R.id.navigation_dashboard:
fm.beginTransaction().hide(active).show(fragment2).commit();
active = fragment2;
Instead of replacing the fragment, use add/remove and create a mechanism for adding and removing fragment stack, also it is not recommended but for the sake of question you can create a singleton fragment, instead of using a new Keyword everything tab is changed, along with that you can have a look at pageOffSet
companion object{
private lateinit var INSTANCE?: HomeFragment() = null
}
fun getInstance(): HomeFragment(){
if(INSTANCE == null){
INSTANCE = HomeFragment()
}
return INSTANCE
}
As we know the ViewPager recreates the fragments when we switch the pages with our BottomNavigationView. I know how to prevent this, use one of these 2 Options:
As i can see your amount of fragments is small and fixed, add in your onCreate() of your
MainHomeActivity.java:
mViewPager = (ViewPager)findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(limit); //limit is a fixed integer
Use a FragmentPagerAdapter as part of your ViewPager. (example provided in link)
UPDATE
In #moalzoabi's case the 2nd option worked. Follow along this post.
I have a BottomNavigationView where I can navigate between fragments. The third fragment is a PreferenceFragment while the other two extend Fragment. I have a simple switch case for replacing fragments but I get an error that SettingsFragment cannot be converted to Fragment.
How can I navigate between these fragments?
BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()) {
case R.id.navigation_home:
toolbar.setTitle("Home");
selectedFragment = HomeFragment.newInstance();
break;
case R.id.navigation_dashboard:
toolbar.setTitle("Dashboard");
selectedFragment = DashboardFragment.newInstance();
break;
case R.id.navigation_settings:
toolbar.setTitle("Settings");
selectedFragment = SettingsFragment.newInstance();
break;
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragmentContainer, selectedFragment);
transaction.commit();
return true;
}
};
Unless you're using the support preference library, PreferenceFragment extends android.app.Fragment, so you need to also extend android.app.Fragment for your other Fragments.
However, since Fragment and PreferenceFragment have been deprecated in API 28, you might want to just convert to the support Fragment and PreferenceFragmentCompat. Be aware that this will mean any Preference libraries you might be using will probably not work until they've been updated.
I'm currently developing a Android studio App using fragment and a bottom navigation bar.
When I click on a navigation bar's item, it's replacing the current fragment by another one which correspond the fragment I wanted for this item.
The problem is, the objects in my fragment are all reset after replacing fragment.
I'm not removing the fragment from the container so I don't really understand why all the objects are reset after doing this.
Here is my code to add and replace fragment to my FrameLayout :
private void setFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.fade_out);
if (getSupportFragmentManager().findFragmentById(R.id.main_frame) == null) {
fragmentTransaction.add(R.id.main_frame, fragment);
}
else
{
fragmentTransaction.replace(R.id.main_frame, fragment);
}
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
and here is the bottom navigation bar code to execute the previous function and change the displayed fragment:
homeFragment = new HomeFragment();
programFragment = new ProgramFragment();
bluetoothFragment = new BluetoothFragment();
mMainNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
test = mMainNav.getMenu().getItem(2);
switch (item.getItemId()) {
case R.id.nav_home:
//mMainNav.setItemBackgroundResource(R.color.colorPrimary);
HQ_logo_IV.setVisibility(View.VISIBLE);
setFragment(homeFragment);
return true;
case R.id.nav_program:
//mMainNav.setItemBackgroundResource(R.color.colorAccent);
HQ_logo_IV.setVisibility(View.INVISIBLE);
setFragment(programFragment);
return true;
case R.id.nav_bluetooth:
//mMainNav.setItemBackgroundResource(R.color.colorPrimaryDark);
HQ_logo_IV.setVisibility(View.INVISIBLE);
setFragment(bluetoothFragment);
return true;
default:
return false;
}
}
});
I found the way to stop this thing.
I used an AsyncTask to refresh my fragment state.
I just put new "yourAsyncTaskName"().execute() at the beginning of my onCreate() method to refresh the fragment when it's created or replaced.
Hope this will help.
I would like to get some input on the best way to structure my app's architecture when using Android's Bottom Navigation View.
Currently I define my BottomNavigationView in my MainActivity. It looks something like this.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationView bottomNavigationView = (BottomNavigationView)findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()){
case R.id.action_home:
selectedFragment = HomeFragment.newInstance();
break;
case R.id.action_search:
selectedFragment = SearchFragment.newInstance();
break;
case R.id.action_message:
selectedFragment = MessageFragment.newInstance();
break;
case R.id.action_profile:
selectedFragment = ProfileFragment.newInstance();
break;
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, selectedFragment);
transaction.commit();
return true;
}
});
//Manually displaying the first fragment - one time only
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, HomeFragment.newInstance());
transaction.commit();
}
The problem is that once I click on one tab, it opens up a fragment, and I would like to have those Fragments open up other Fragments/Activities (i.e:
I open the profile tab (`ProfileFragment` loads)
I click on a button from `ProfileFragment`, and from this the `SignUpFragment` loads
After running into many bugs, I've researched on how to architect my app, but i've found mixed results. Would anyone know the correct way of using a BottomNavigationView with Fragments, and in those fragments I can load more Activities/fragments. A huge thanks in advance.
I did a navigation drawer, and I’ve set some items and normally when I select an item the current fragment will be changed by a new one, it's not the case for me, the first Activity still displayed even if the fragments change. This is my onNavigationDrawerItemSelectedmethod and it's clear I change the fragment every time i click on a new one.
#Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
// TODO : Added
switch(position) {
/*case 0 :
fragmentManager.beginTransaction()
.replace(R.id.container, new ProfilFrgement())
.commit();
break;*/
case 1:
fragmentManager.beginTransaction()
.replace(R.id.container, new SpotFragement())
.commit();
break;
case 2:
fragmentManager.beginTransaction()
.replace(R.id.container, new SessionsFragement())
.commit();
break;
/*case 3:
fragmentManager.beginTransaction()
.replace(R.id.container, new EventsFragment())
.commit();
break;*/
}
}
I think my problem is a change always the same container. So what I need its getting the current fragment ID
Sorry for too late but I have a solution to get fragment ID. You can use name of Fragment Class as an Identifier not the ID. Use a static String variable to store class name.
public class Activity{
...
static String currentFragment = null;
...
...
#Override
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.nav_one:
setFragment(new oneFragment());
break;
case R.id.nav_two:
setFragment(new twoFragment());
break;
}
return true;
}
public static void setFragment(#NonNull Fragment f) {
if(!f.getClass().getName().equals(currentFragment)){
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.container, f);
fragmentTransaction.commit();
currentFragment = f.getClass().getName();
}
...
}
What is current fragment ID here? Ur id is R.id.container which is only one rt? then what is the question about "How can i get the current Fragment ID"?
If question is to find which is the current fragment is shown to user? If yes then
Fragment ft = getSupportFragmentManager().findFragmentById(R.id.container);
if (ft instanceof SpotFragement) {
// navigation drawer item 1 and current fragment is SpotFragment.
} else if (ft instanceof SessionsFragement) {
}
Make sure that your container styling is correct.
Check following values of container once -
android:layout_width
android:layout_height