Android Bottom Navigation Bar in activities - android

I am developing a car rental app and right now I have 3 fragments in my app (Home - where all the cars are displayed from a recyclerview , Orders - where user's bookings are shown , Profile - user profile). I can switch beetween these 3 fragments from my bottom navigationbar.
Now I created onclick listeners for every car on home page. When I click on a car it sends me to a new activity "activity_car_detail.xml" which contains specific information about the selected car. My question is: how can I make the navigation bar to appear on this Car Detail activity? Should I use fragment instead of activity or what should I do?
This is the code for the Main Activity which contains the bottom navigation bar:
public class MainActivity extends AppCompatActivity {
public static ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation);
bottomNav.setOnNavigationItemSelectedListener(navListener);
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new HomeFragment()).commit();
}
private BottomNavigationView.OnNavigationItemSelectedListener navListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()) {
case R.id.nav_home:
selectedFragment = new HomeFragment();
break;
case R.id.nav_orders:
selectedFragment = new OrdersFragment();
break;
case R.id.nav_profile:
selectedFragment = new ProfileFragment();
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, selectedFragment).commit();
return true;
}
};
}

I suggest using the Navigation component instead of Fragment transactions. Also this will fix your issue and it will remove boilerplate code. Read more about it's documentation here.

Related

BottomNavigationView with setOnItemSelectedListener()

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/

How to Stop Fragment from Reloading When Changing Tabs?

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.

Show loading screen while activity is loading in background

I have an app with bottomnavigationview using which I can navigate between five different fragments/pages. When I switch over to a different page, the app waits(i.e loads the page) for 0.5 - 1 second and then displays it. I want that on moving to another page, the app shows a loading screen on the foreground while the page loads in the background, and when it's done loading the loading screen goes away and the loaded page appears? How can I do that? Making the loading screen is not a problem but implementing it in the way I want is.
My MainActivity.java:
public class MainActivity extends AppCompatActivity {
RelativeLayout btmnavl;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new Home()).commit();
LinearLayout team = findViewById(R.id.team_lay);
BottomNavigationView bottomNavigationView = findViewById(R.id.btmnav);
bottomNavigationView.setOnNavigationItemSelectedListener(navlistner);
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new Live()).commit();
}
private BottomNavigationView.OnNavigationItemSelectedListener navlistner =
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()){
case R.id.live:
selectedFragment = new Live();
hide();
break;
case R.id.home:
selectedFragment = new Home();
break;
case R.id.schedule:
selectedFragment = new Schedule();
break;
case R.id.feed:
selectedFragment = new Feed();
break;
case R.id.recent:
selectedFragment = new Recent();
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
selectedFragment).commit();
return true;
}
};
private void hide(){
btmnavl = findViewById(R.id.btmnavl);
btmnavl.setVisibility(View.GONE);
}
}
To add a progress bar which is only visible when the page is loading, add the following to your activity XML:
<RelativeLayout
android:id="#+id/loadingPanel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:elevation="4dp">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
android:indeterminateTintMode="src_atop"/>
</RelativeLayout>
Then you can fetch it with loadingPanel = (RelativeLayout) findViewById(R.id.loadingPanel);
And set visibility with:
loadingPanel.setVisibility(View.GONE);
loadingPanel.setVisibility(View.VISIBLE);
In your case, you can set it to GONE right before the .commit(), so:
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new Live());
loadingPanel.setVisibility(View.GONE);
transaction.commit();
This should work for you I believe, just don't forget to set it back to VISIBLE when you load other fragments, and edit the above XML to fit your specific layout better.

recreate conditioned fragments without button

In my Application there are four ButtonNavigationView tabs with fragments, i want 2 of them to refresh every time i click on them and the other 2 to not refresh every time i click on them , how can i get that?
Home Activity
final Fragment factorsFragment = new FactorsFragment();
final Fragment newFactorFragment = new NewFactorFragment();
final Fragment productsFragment = new ProductsFragment();
final Fragment checkList = new CheckList();
final FragmentManager fm = getSupportFragmentManager();
Fragment active = newFactorFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
fm.beginTransaction().add(R.id.fragment_container, productsFragment, "4").hide(productsFragment).commit();
fm.beginTransaction().add(R.id.fragment_container, factorsFragment, "3").hide(factorsFragment).commit();
fm.beginTransaction().add(R.id.fragment_container, checkList, "2").hide(checkList).commit();
fm.beginTransaction().add(R.id.fragment_container, newFactorFragment, "1").commit();
SQLiteStudioService.instance().start(this);
}
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
fm.beginTransaction().hide(active).show(factorsFragment).commit();
active = factorsFragment;
return true;
case R.id.navigation_dashboard:
fm.beginTransaction().hide(active).show(newFactorFragment).commit();
active = newFactorFragment;
return true;
case R.id.navigation_notifications:
fm.beginTransaction().hide(active).show(productsFragment).commit();
active = productsFragment;
return true;
case R.id.navigation_checklist:
fm.beginTransaction().hide(active).show(checkList).commit();
active = checkList;
return true;
}
return false;
}
};
i want factorFragment and productFragment to refresh without adding a swiperefreshlayout or custom refresh button
my problem is all of my fragments don't refresh on tab change, because i am just making them show and hide , but i want 2 of them to refresh.
Call all the functions of your factorFragment and productFragment in onResume of the respective fragments. Changes will reflect as you are calling the methods again in onResume.
Fragment has offset. So if you are loading one fragment in activity the next few(depends on what you set or the default offset) fragments also get initialized. That's why it will be wise to recall your functions in onResume.

Show and hide fragment within an activity

I'm currently creating functionality to change Fragments using bottom navigation. But instead of destroying them and recreating them, I want to simply hide and show the fragments to preserve the member variables.
I've tried replace(), hide() and show() but haven't managed the get it right, I'm getting animation errors which I'm not able to track down.
I also can't find an example of switching fragments within an AppCompatActivity.
public class MainActivity extends AppCompatActivity {
PassengerFragment passengerFragment;
DriverFragment driverFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation);
bottomNav.setOnNavigationItemSelectedListener(navListener);
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
new PassengerFragment()).commit();
}
// this handles the bottom navigation so when you click an item it changes fragment
private BottomNavigationView.OnNavigationItemSelectedListener navListener =
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
Fragment selectedFragment = null;
switch (menuItem.getItemId()) {
case R.id.nav_passenger:
selectedFragment = passengerFragment;
break;
case R.id.nav_driver:
if (driverFragment==null) {
selectedFragment = new DriverFragment();
}
else {
selectedFragment = driverFragment;
}
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
selectedFragment).commit(); <---- line 54
return true;
}
};
}
ERROR
Java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference
at android.support.v4.app.BackStackRecord.doAddOp(BackStackRecord.java:396)
at android.support.v4.app.BackStackRecord.replace(BackStackRecord.java:444)
at android.support.v4.app.BackStackRecord.replace(BackStackRecord.java:434)
at je.digital.kevin_pickmeup.MainActivity$1.onNavigationItemSelected(MainActivity.java:54)
That is because you are trying do replace with Fragment which are null. You have created passengerFragment and driverFragment as fields or global variables and than you are trying to use them but in some cases especially passengerFragment is null. If you are trying to keep the data in Fragments even they are replaced you can use addToBackStack but you will need to manage not to putting too much to back stack probably by checking getSupportFragmentManager().getBackStackEntryCount() and removing if there are more than 1 using popBackStack() or save the data in Bundle on onDestroyView and restore that data in onCreateView:
just needed better if statements to handle all the cases.
private BottomNavigationView.OnNavigationItemSelectedListener navListener =
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
Fragment passengerFragment = getSupportFragmentManager().findFragmentByTag("A");
Fragment driverFragment = getSupportFragmentManager().findFragmentByTag("B");
switch (menuItem.getItemId()) {
case R.id.nav_passenger:
if(passengerFragment.isHidden()) {
getSupportFragmentManager().beginTransaction().show(passengerFragment).commit();
getSupportFragmentManager().beginTransaction().hide(driverFragment).commit();
}
break;
case R.id.nav_driver:
if(driverFragment==null) {
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, new DriverFragment(),"B").commit();
getSupportFragmentManager().beginTransaction().hide(passengerFragment).commit();
}
else {
if(driverFragment.isHidden()) {
getSupportFragmentManager().beginTransaction().show(driverFragment).commit();
getSupportFragmentManager().beginTransaction().hide(passengerFragment).commit();
}
}
break;
}
return true;
}
};

Categories

Resources