6

We have bottom navigation tabs(4) and each tab is having fragment in it. Could anyone help(give idea) how to design the structure in MVVM way with keeping the fragment state for each tab. I know that this is not the place for poor questions but I am looking for conceptual advice. To accomplish it in a best possible way.

Medet
  • 123
  • 2
  • 8
  • looking for same information, how'd you did it? – ateebahmed Mar 24 '19 at 23:05
  • 1
    @ateebahmed I think this particular [repo](https://github.com/DroidKaigi/conference-app-2018) could be good example for you. – Medet Mar 27 '19 at 07:16
  • I solved my problem using this. I hope it will work for you https://stackoverflow.com/questions/68395330/best-practice-to-implement-mvvm-in-fragment-using-bottom-navigation-android-kotl/68395546?noredirect=1#comment120884077_68395546 – Saad Iftikhar Jul 16 '21 at 07:32

2 Answers2

0

With the latest arch components life become so much easer. Now I don't have to care about keeping my fragments alive as long as I implement business logic (state) inside ViewModel i am fine. It survives the config changes. If you ask me how about when system kills your app in order to claim the memory, with latest ViewModel feature you can manage this inside you ViewModel. So you can eliminate extra boilerplate code/communication code between View and ViewModel to pass savedState (e.g id, url, etc..). This would be true separation of concern.

Medet
  • 123
  • 2
  • 8
-3

Google (through Nick Butcher‏) announced the release of the v25 of the Android Design Support Library which includes the new BottomNavigationView.

menu.xml

Define navigation items (Fragments items) in the menu resource file

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
    android:id="@+id/action_item1"
    android:icon="@drawable/icon1"
    android:title="Menu1"
/>
<item

    android:id="@+id/action_item2"
    android:icon="@drawable/icon2"
    android:title="Menu2"/>
<item
    android:id="@+id/action_item3"
    android:icon="@drawable/icon3"
    android:title="Menu3" />
<item
    android:id="@+id/action_item4"
    android:icon="@drawable/icon4"
    android:title="Menu4" />

</menu>

activity_main.xml

ADD the actual BottomNavigationView to the layout.

  <RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:local="http://schemas.android.com/apk/res-auto"
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="?attr/actionBarSize"
        android:background="@color/colorPrimary"
        local:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        local:popupTheme="@style/ThemeOverlay.AppCompat.Light" />


    <FrameLayout
        android:id="@+id/frame_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/navigation"
        android:layout_below="@id/toolbar"
        android:animateLayoutChanges="true">

    </FrameLayout>

    <android.support.design.widget.BottomNavigationView
        android:id="@+id/navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="@drawable/rbtn_selector"
        android:paddingTop="@dimen/_2sdp"
        app:itemIconTint="@drawable/selector_bottom"
        app:itemTextColor="@drawable/selector_bottom"
        app:elevation="@dimen/_8sdp"
        app:menu="@menu/menu"/>


</RelativeLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {

        bottomNavigationView = (BottomNavigationView)findViewById(R.id.navigation);

  //If you want to remove slide animation of bottomview  with Helper Class 

 BottomNavigationViewHelper.removeShiftMode(bottomNavigationView);
        Menu m = bottomNavigationView.getMenu();


 bottomNavigationView.setOnNavigationItemSelectedListener
            (new BottomNavigationView.OnNavigationItemSelectedListener() {
                @Override
                public boolean onNavigationItemSelected(@NonNull MenuItem item) {


                    if (getSupportActionBar() != null){
                        getSupportActionBar().setDisplayHomeAsUpEnabled(false);
                        getSupportActionBar().setHomeButtonEnabled(false);
                    }



                    android.app.Fragment selectedFragment = null;
                    switch (item.getItemId()) {
                        case R.id.action_item1:
                            selectedFragment = Fragment1.newInstance();
                            toolbar.setTitle("Fragment1");
                            break;
                        case R.id.action_item2:
                            selectedFragment = Fragment2.newInstance();
                            toolbar.setTitle("Fragment2");
                            break;
                        case R.id.action_item3:
                            selectedFragment = Fragment3.newInstance();
                            toolbar.setTitle("Fragment3");
                            break;
                        case R.id.action_item4:
                            selectedFragment = Fragment4.newInstance();
                            toolbar.setTitle("Fragment4");
                            break;
                        default:
                            selectedFragment = Fragment1.newInstance();
                            toolbar.setTitle("Fragment1");
                            break;

                    }
                    android.app.FragmentTransaction transaction = getFragmentManager().beginTransaction();
                    transaction.replace(R.id.frame_layout, selectedFragment);
                    transaction.commit();
                    return true;
                }
            });

    //Manually displaying the first fragment - one time only



    android.app.FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(R.id.frame_layout, Fragment1.newInstance());
    transaction.commit();

  }

This Helper class for Remove Shifting animation

static class BottomNavigationViewHelper {

    public static void removeShiftMode(BottomNavigationView view) {
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
        try {
            Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
            shiftingMode.setAccessible(true);
            shiftingMode.setBoolean(menuView, false);
            shiftingMode.setAccessible(false);
            for (int i = 0; i < menuView.getChildCount(); i++) {
                BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
             item.setShiftingMode(false);
                // set once again checked value, so view will be updated
                item.setChecked(item.getItemData().isChecked());
            }
        } catch (NoSuchFieldException e) {
            Log.e("ERROR NO SUCH FIELD", "Unable to get shift mode field");
        } catch (IllegalAccessException e) {
            Log.e("ERROR ILLEGAL ALG", "Unable to change value of shift mode");
        }
    }
}

Each Fragment as a menu item **Fragmen1.java**

public class Fragmen1 extends android.app.Fragment {

public static Fragmen1 newInstance() {
    Fragmen1 fragment = new Fragmen1();
    return fragment;
}
  @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

}
Harsh Bhavsar
  • 1,561
  • 4
  • 21
  • 39