Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Support Design: BottomNavigationView

I am trying to achieve something like this https://material.google.com/components/bottom-navigation.html#bottom-navigation-behavior

But recycler view is hiding below toolbar and no effect is on BottomNavigationView

Below is my code

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">


        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
    </android.support.design.widget.AppBarLayout>


    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">


        <android.support.design.widget.BottomNavigationView
            android:id="@+id/nm_bottom"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:background="@color/colorPrimaryDark"
            android:foregroundTint="@color/colorAccent"
            app:itemIconTint="@android:color/white"
            app:itemTextColor="@android:color/white"
            app:menu="@menu/nav_menu" />

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@id/nm_bottom"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />
    </RelativeLayout>

</android.support.design.widget.CoordinatorLayout>

item.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:padding="4dp">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cardElevation="2dp">

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="?android:attr/listPreferredItemHeight"
            android:padding="4dp">

            <ImageView
                android:id="@+id/icon"
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
                android:layout_alignParentBottom="true"
                android:layout_alignParentTop="true"
                android:layout_marginRight="6dip"
                android:contentDescription="TODO"
                android:src="@drawable/ic_storage" />

            <TextView
                android:id="@+id/secondLine"
                android:layout_width="fill_parent"
                android:layout_height="26dip"
                android:layout_alignParentBottom="true"
                android:layout_alignParentRight="true"
                android:layout_toRightOf="@id/icon"
                android:ellipsize="marquee"
                android:text="Description"
                android:textSize="12sp" />

            <TextView
                android:id="@+id/firstLine"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_above="@id/secondLine"
                android:layout_alignParentRight="true"
                android:layout_alignParentTop="true"
                android:layout_alignWithParentIfMissing="true"
                android:layout_toRightOf="@id/icon"
                android:gravity="center_vertical"
                android:text="Example application"
                android:textSize="16sp" />

        </RelativeLayout>
    </android.support.v7.widget.CardView>
</FrameLayout>




public class MainActivity extends AppCompatActivity implements BottomNavigationView.OnNavigationItemSelectedListener {

            private static final Logger logger = Logger.getLogger(MainActivity.class.getSimpleName());

            private BottomNavigationView navigationView;
            private RecyclerView mRecyclerView;
            private MyAdapter mAdapter;

            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                initViews();
            }

            private void initViews() {
                navigationView = (BottomNavigationView) findViewById(R.id.nm_bottom);
                navigationView.setOnNavigationItemSelectedListener(this);
                mRecyclerView = (RecyclerView) findViewById(R.id.rv);

                // use this setting to improve performance if you know that changes
                // in content do not change the layout size of the RecyclerView
                mRecyclerView.setHasFixedSize(true);

                // use a linear layout manager
                LinearLayoutManager mLayoutManager = new LinearLayoutManager(this);
                mRecyclerView.setLayoutManager(mLayoutManager);

                // specify an adapter (see also next example)
                List<String> myDataset = new ArrayList<>();
                for (int i = 0; i < 100; i++) {
                    myDataset.add("Index #" + i);
                }
                mAdapter = new MyAdapter(myDataset);
                mRecyclerView.setAdapter(mAdapter);
            }

            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {

                return false;
            }
        }

        public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
            private List<String> mDataset;

            // Provide a reference to the views for each data item
            // Complex data items may need more than one view per item, and
            // you provide access to all the views for a data item in a view holder
            public class ViewHolder extends RecyclerView.ViewHolder {
                // each data item is just a string in this case
                public TextView txtHeader;
                public TextView txtFooter;

                public ViewHolder(View v) {
                    super(v);
                    txtHeader = (TextView) v.findViewById(R.id.firstLine);
                    txtFooter = (TextView) v.findViewById(R.id.secondLine);
                }
            }

            public void add(int position, String item) {
                mDataset.add(position, item);
                notifyItemInserted(position);
            }

            public void remove(String item) {
                int position = mDataset.indexOf(item);
                mDataset.remove(position);
                notifyItemRemoved(position);
            }

            // Provide a suitable constructor (depends on the kind of dataset)
            public MyAdapter(List<String> myDataset) {
                mDataset = myDataset;
            }

            // Create new views (invoked by the layout manager)
            @Override
            public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                           int viewType) {
                // create a new view
                View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler_view, parent, false);
                // set the view's size, margins, paddings and layout parameters
                ViewHolder vh = new ViewHolder(v);
                return vh;
            }

            // Replace the contents of a view (invoked by the layout manager)
            @Override
            public void onBindViewHolder(ViewHolder holder, int position) {
                // - get element from your dataset at this position
                // - replace the contents of the view with that element
                final String name = mDataset.get(position);
                holder.txtHeader.setText(mDataset.get(position));
                holder.txtHeader.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        remove(name);
                    }
                });

                holder.txtFooter.setText("Footer: " + mDataset.get(position));

            }

            // Return the size of your dataset (invoked by the layout manager)
            @Override
            public int getItemCount() {
                return mDataset.size();
            }

        }
like image 437
silentsudo Avatar asked Oct 20 '16 10:10

silentsudo


People also ask

How to use BottomNavigationView in Android?

BottomNavigationView makes it easy for users to explore and switch between top-level views with a single tap. There should be a minimum of 3 top-level views and a maximum of 5. If Destinations are more than 5 then use the Navigation Drawer. When the user taps on the icon it will change the top-level view accordingly.

What is BottomNavigationView?

com.google.android.material.bottomnavigation.BottomNavigationView. Represents a standard bottom navigation bar for application. It is an implementation of material design bottom navigation. Bottom navigation bars make it easy for users to explore and switch between top-level views in a single tap.

How do I add more than 5 items in BottomNavigationView?

Create a menu resource with up to 5 navigation targets (BottomNavigationView does not support more than 5 items). Secondly, Having 5 or more items in BottomNavigation is a bad design in terms of User Experience. Even 4 is a stretch. If you need more than 5 items, BottomNavigation is not suitable for you.


2 Answers

Edit: Here is a simple sample showing how to implement scrolling behavior https://github.com/sjthn/BottomNavigationViewBehavior

Change your XML to this:

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">


        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:title="@string/app_name" />
    </android.support.design.widget.AppBarLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <android.support.design.widget.BottomNavigationView
        android:id="@+id/nm_bottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimaryDark"
        android:foregroundTint="@color/colorAccent"
        app:itemIconTint="@android:color/white"
        app:itemTextColor="@android:color/white"
        app:layout_anchor="@+id/rv"
        app:layout_anchorGravity="bottom"
        app:menu="@menu/nav_menu" />

</android.support.design.widget.CoordinatorLayout>
like image 71
Srijith Avatar answered Oct 29 '22 19:10

Srijith


So with little help from @Srijith i am able to animate the way it is given in link.

Part of this answer is

public class BottomNavigationBehavior<V extends View> extends VerticalScrollingBehavior<V> {
    private static final Interpolator INTERPOLATOR = new LinearOutSlowInInterpolator();
    private int mBottomNavigationViewId;
    private boolean hidden = false;
    private ViewPropertyAnimatorCompat mTranslationAnimator;
    private BottomNavigationView navigationView;
    private View mTabsHolder;

    public BottomNavigationBehavior() {
        super();
    }

    public BottomNavigationBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        mBottomNavigationViewId = R.id.nm_bottom;
    }

    @Override
    public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
        boolean layoutChild = super.onLayoutChild(parent, child, layoutDirection);
        if (navigationView == null && mBottomNavigationViewId != View.NO_ID) {
            navigationView = findTabLayout(child);
            getTabsHolder();
        }
        return layoutChild;
    }

    private BottomNavigationView findTabLayout(View child) {
        return (BottomNavigationView) child.findViewById(mBottomNavigationViewId);
    }

    @Override
    public void onNestedVerticalOverScroll(CoordinatorLayout coordinatorLayout, V child, @ScrollDirection int direction, int currentOverScroll, int totalOverScroll) {
    }

    @Override
    public void onDirectionNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed, @ScrollDirection int scrollDirection) {
        handleDirection(child, scrollDirection);
    }

    private void handleDirection(V child, int scrollDirection) {
        if (scrollDirection == ScrollDirection.SCROLL_DIRECTION_DOWN && hidden) {
            hidden = false;
            animateOffset(child, 0);
        } else if (scrollDirection == ScrollDirection.SCROLL_DIRECTION_UP && !hidden) {
            hidden = true;
            animateOffset(child, child.getHeight());
        }
    }

    @Override
    protected boolean onNestedDirectionFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY, @ScrollDirection int scrollDirection) {
        handleDirection(child, scrollDirection);
        return true;
    }

    private void animateOffset(final V child, final int offset) {
        ensureOrCancelAnimator(child);
        mTranslationAnimator.translationY(offset).start();
        animateTabsHolder(offset);
    }

    private void animateTabsHolder(int offset) {
        if (mTabsHolder != null) {
            offset = offset > 0 ? 0 : 1;
            ViewCompat.animate(mTabsHolder).alpha(offset).setDuration(200).start();
        }
    }


    private void ensureOrCancelAnimator(V child) {
        if (mTranslationAnimator == null) {
            mTranslationAnimator = ViewCompat.animate(child);
            mTranslationAnimator.setDuration(100);
            mTranslationAnimator.setInterpolator(INTERPOLATOR);
        } else {
            mTranslationAnimator.cancel();
        }
    }

    private void getTabsHolder() {
        if (navigationView != null) {
            mTabsHolder = navigationView.getChildAt(0);
        }
    }

    public static <V extends View> BottomNavigationBehavior<V> from(V view) {
        ViewGroup.LayoutParams params = view.getLayoutParams();
        if (!(params instanceof CoordinatorLayout.LayoutParams)) {
            throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");
        }
        CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params)
                .getBehavior();
        if (!(behavior instanceof BottomNavigationBehavior)) {
            throw new IllegalArgumentException(
                    "The view is not associated with ottomNavigationBehavior");
        }
        return (BottomNavigationBehavior<V>) behavior;
    }

    public void setTabLayoutId(@IdRes int tabId) {
        this.mBottomNavigationViewId = tabId;
    }
}

public abstract class VerticalScrollingBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {

    private int mTotalDyUnconsumed = 0;
    private int mTotalDy = 0;
    @ScrollDirection
    private int mOverScrollDirection = ScrollDirection.SCROLL_NONE;
    @ScrollDirection
    private int mScrollDirection = ScrollDirection.SCROLL_NONE;

    public VerticalScrollingBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public VerticalScrollingBehavior() {
        super();
    }

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({ScrollDirection.SCROLL_DIRECTION_UP, ScrollDirection.SCROLL_DIRECTION_DOWN})
    public @interface ScrollDirection {
        int SCROLL_DIRECTION_UP = 1;
        int SCROLL_DIRECTION_DOWN = -1;
        int SCROLL_NONE = 0;
    }


    /*
       @return Overscroll direction: SCROLL_DIRECTION_UP, CROLL_DIRECTION_DOWN, SCROLL_NONE
   */
    @ScrollDirection
    public int getOverScrollDirection() {
        return mOverScrollDirection;
    }


    /**
     * @return Scroll direction: SCROLL_DIRECTION_UP, SCROLL_DIRECTION_DOWN, SCROLL_NONE
     */

    @ScrollDirection
    public int getScrollDirection() {
        return mScrollDirection;
    }


    /**
     * @param coordinatorLayout
     * @param child
     * @param direction         Direction of the overscroll: SCROLL_DIRECTION_UP, SCROLL_DIRECTION_DOWN
     * @param currentOverScroll Unconsumed value, negative or positive based on the direction;
     * @param totalOverScroll   Cumulative value for current direction
     */
    public abstract void onNestedVerticalOverScroll(CoordinatorLayout coordinatorLayout, V child, @ScrollDirection int direction, int currentOverScroll, int totalOverScroll);

    /**
     * @param scrollDirection Direction of the overscroll: SCROLL_DIRECTION_UP, SCROLL_DIRECTION_DOWN
     */
    public abstract void onDirectionNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed, @ScrollDirection int scrollDirection);

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes) {
        return (nestedScrollAxes & View.SCROLL_AXIS_VERTICAL) != 0;
    }

    @Override
    public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes) {
        super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
    }

    @Override
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
        super.onStopNestedScroll(coordinatorLayout, child, target);
    }

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
        if (dyUnconsumed > 0 && mTotalDyUnconsumed < 0) {
            mTotalDyUnconsumed = 0;
            mOverScrollDirection = ScrollDirection.SCROLL_DIRECTION_UP;
        } else if (dyUnconsumed < 0 && mTotalDyUnconsumed > 0) {
            mTotalDyUnconsumed = 0;
            mOverScrollDirection = ScrollDirection.SCROLL_DIRECTION_DOWN;
        }
        mTotalDyUnconsumed += dyUnconsumed;
        onNestedVerticalOverScroll(coordinatorLayout, child, mOverScrollDirection, dyConsumed, mTotalDyUnconsumed);
    }

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
        if (dy > 0 && mTotalDy < 0) {
            mTotalDy = 0;
            mScrollDirection = ScrollDirection.SCROLL_DIRECTION_UP;
        } else if (dy < 0 && mTotalDy > 0) {
            mTotalDy = 0;
            mScrollDirection = ScrollDirection.SCROLL_DIRECTION_DOWN;
        }
        mTotalDy += dy;
        onDirectionNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, mScrollDirection);
    }


    @Override
    public boolean onNestedFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY, boolean consumed) {
        super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
        mScrollDirection = velocityY > 0 ? ScrollDirection.SCROLL_DIRECTION_UP : ScrollDirection.SCROLL_DIRECTION_DOWN;
        return onNestedDirectionFling(coordinatorLayout, child, target, velocityX, velocityY, mScrollDirection);
    }

    protected abstract boolean onNestedDirectionFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY, @ScrollDirection int scrollDirection);

    @Override
    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY) {
        return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
    }

    @Override
    public WindowInsetsCompat onApplyWindowInsets(CoordinatorLayout coordinatorLayout, V child, WindowInsetsCompat insets) {

        return super.onApplyWindowInsets(coordinatorLayout, child, insets);
    }

    @Override
    public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) {
        return super.onSaveInstanceState(parent, child);
    }

}

All this answer came from this guy: https://medium.com/@nullthemall/bottom-navigation-behavior-388b9b206667#.potyetdkb

Entire Project is located here

like image 31
silentsudo Avatar answered Oct 29 '22 21:10

silentsudo