I am trying to build app with BottomNavigationView and I set setOnItemSelectedListener() method to bottom navigation so I can do what I want when user select one of the menu in bottom navigation.
everything is good when I don't set setOnItemSelectedListener(), but when I set setOnItemSelectedListener() method then the fragment is not updated automatically when user select the bottom navigation menu.
I consider if that do i have to handle fragment transaction manually when I set this method?
thanks ^^
Yes. You need to manually replace the fragment item on onNavigationItemSelected
Example:
private BottomNavigationView.OnNavigationItemSelectedListener navListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
// By using switch we can easily get
// the selected fragment
// by using there id.
Fragment selectedFragment = null;
switch (item.getItemId()) {
case R.id.algorithm:
selectedFragment = new AlgorithmFragment();
break;
case R.id.course:
selectedFragment = new CourseFragment();
break;
case R.id.profile:
selectedFragment = new ProfileFragment();
break;
}
// It will help to replace the
// one fragment to other.
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, selectedFragment)
.commit();
return true;
}
};
You can find a good tutorial here: https://www.geeksforgeeks.org/bottomnavigationview-inandroid/
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 setup of 3 Fragments inside my main activity and want to navigate them using the BottomNavigationView. I want to add them once and then just switch between them without actually destroying the Fragments. Everything works fine except that the first fragment added to the SupportFragmentManager always disappears (tried changing the order so the problem is not with the Fragments themselves). Actually, it doesn't disappear but the last Fragment that occupied the container shows up.
Eg. I go to position 3, Fragment 3 shows up in the container and then click on position 1, Fragment 3 will still occupy the container. But if I tap position 2 Fragment 2 will appear. How I'm adding the Fragments:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.container, fragment1); //whatever gets added here ends up being invisible
ft.commitAllowingStateLoss();
ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.container, fragment2);
ft.commitAllowingStateLoss();
ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.container, fragment3);
ft.commitAllowingStateLoss();
How I'm switching between them using the OnNavigationItemSelectedListener:
private BottomNavigationView.OnNavigationItemSelectedListener navigation_listener =
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
Fragment previousFragment = getSupportFragmentManager().findFragmentById(R.id.container);
switch(item.getItemId()){
case R.id.bottom_navigation_bar_position1:
selectedFragment = fragment1;
break;
case R.id.bottom_navigation_bar_position2:
selectedFragment = fragment2;
break;
case R.id.bottom_navigation_bar_position3:
selectedFragment = fragment3;
break;
}
getSupportFragmentManager().beginTransaction().hide(previousFragment).commit();
getSupportFragmentManager().beginTransaction().show(selectedFragment).commit();
return true;
}
};
The XML menu navigation:
<item
android:id="#+id/bottom_navigation_bar_position1"
android:title="Title1"
android:icon="#drawable/ic1"
/>
<item
android:id="#+id/bottom_navigation_bar_position2"
android:title="Title2"
android:icon="#drawable/ic2"
/>
<item
android:id="#+id/bottom_navigation_bar_position3"
android:title="Title3"
android:icon="#drawable/ic3"
/>
Btw. just using replace() instead of show and hide works but that's not the goal...
I've also tested whether the first added Fragment exits (and doesn't get destroyed) and it indeed exists...
Thanks!
Instead of trying to show and hide fragment I solved the problem by managing the Fragments using a ViewPager and a SectionsPageAdapter. Once you link these two, use ViewPager.setOffscreenPageLimit(3) to make sure no Fragments get destroyed. My BottomNavigationView.OnNavigationItemSelectedListener looks like this now:
private BottomNavigationView.OnNavigationItemSelectedListener navigation_listener =
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch(item.getItemId()){
case R.id.bottom_navigation_bar_position1:
tab_view_pager.setCurrentItem(0);
return true;
case R.id.bottom_navigation_bar_position2:
tab_view_pager.setCurrentItem(1);
return true;
case R.id.bottom_navigation_bar_position3:
tab_view_pager.setCurrentItem(2);
return true;
}
return false;
}
};
You have to set 0th position item selected for BottomNavigationView.OnNavigationItemSelectedListener. Find Menu bottom_navigation_bar_position1
I used this in my code, please refactor according to your needs
BottomNavigationView navigation = findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(this);
Menu menu = navigation.getMenu();
this.onNavigationItemSelected(menu.findItem(R.id.navigation_doc));
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 created an activity with a bottom navigation bar.
I googled a lot things about it but now I don't know how to handle this exactly.
Before, I just started another activity when the user clicks the bottom navigation but I think it's not good.
How can I switch between the tabs?
Do I have to work with fragments? And what about 'setContentView(int layoutResID)'? How can I do that? I'm confused...
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
return true;
case R.id.navigation_dashboard:
startActivity(dashboardActivity);
return true;
case R.id.navigation_notifications:
startActivity(dashboardActivity);
return true;
}
return false;
}
};
Thank you very much for your help - I hope, you understood what I mean.
Activity transition is always expensive and we should switch from one activity to another only when we are switching the context. A fragment is a portion of UI in an activity. Same fragment can be used with multiple activities. Just like activity a fragment has its own lifecycle and setContentView(int layoutResID) can be set to different layout in OnCreate of fragment.
This link explains more on when to use activity or fragment.
Android developer guide on Fragments
Code path tutorial on bottom navigation views.
Please refer to :-
https://github.com/waleedsarwar86/BottomNavigationDemo
and complete explanation in
http://waleedsarwar.com/posts/2016-05-21-three-tabs-bottom-navigation/
You will get a running code with the explanation here.
Bottom Navigation View is a navigation bar introduced in android library to make it easy to switch between views with a single tap. It can although be used for almost any purpose, but is most commonly used to switch between fragments with a single tap. Its use for opening activities is somewhat absurd, since it ignores its most important functionality of switching the views with a single tap. There are many good articles and blogs out there in this regard, one of which is:
https://medium.com/#hitherejoe/exploring-the-android-design-support-library-bottom-navigation-drawer-548de699e8e0
Hope this solves your doubt..
bottomNavigationView.setOnNavigationItemSelectedListener
(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()) {
case R.id.action_item1:
selectedFragment = ItemOneFragment.newInstance();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, selectedFragment);
transaction.commit();
// selectedFragment.getChildFragmentManager().beginTransaction();
break;
case R.id.action_item2:
selectedFragment = ItemTwoFragment.newInstance();
FragmentTransaction transactiona = getSupportFragmentManager().beginTransaction();
transactiona.replace(R.id.frame_layout, selectedFragment);
transactiona.commit();
// selectedFragment = ItemThreeFragment.newInstance();
break;
case R.id.action_item3:
// selectedFragment = ItemOneFragment.newInstance();
Intent intent=new Intent(MainView.this, YoutActivityLive.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
// selectedFragment = ItemTwoFragment.newInstance();
break;
case R.id.action_item5:
selectedFragment = ItemOneFragment.newInstance();
FragmentTransaction transactionb = getSupportFragmentManager().beginTransaction();
transactionb.replace(R.id.frame_layout, selectedFragment);
transactionb.commit();
// selectedFragment = ItemFiveFragment.newInstance();
break;
}
return true;
}
});