Android 底部导航菜单的使用

Android 底部导航停留在屏幕的底部,在应用程序的顶层视图之间提供导航。这是在向后兼容的设计支持库中引入的。当应用程序有三到五个顶级导航时,应该使用底部导航。本文将介绍底部导航的基础知识,并将其与 Fragment相结合。我们还将学习如何通过通过 HTTP 调用获取 JSON 来加载第一个带有网格数据的片段(使用 RecyclerView)。

底部导航

使用 Bottom Navigationview 组件可以轻松添加底部导航。您必须使用约束关系或相对关系属性,使它出现在屏幕底部。

<?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">

    <FrameLayout
        android:id="@+id/frame_container"
        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/navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="?android:attr/windowBackground"
        app:itemBackground="@color/bgBottomNavigation"
        android:foreground="?attr/selectableItemBackground"
        app:itemIconTint="@android:color/white"
        app:itemTextColor="@android:color/white"
        app:menu="@menu/navigation" />

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

这里有一些重要的属性需要记录下来。

app:menu — 菜单资源文件,用于显示导航项以及图标和文本。 app:itemBackground — 将背景颜色应用于底部导航。 app:itemTextColor — 底部导航项的文本颜色。 app:itemIconTint — 底部导航项的图标颜色。

何时使用底部导航? 根据设计规范,应根据标准使用以下导航。

  • Navigation Drawer – 当顶级导航有六个以上的目的地时使用。
  • Tabs – 当有两个导航目的地时使用。
  • Bottom Navigation – 当有三到五个顶级目的地时使用。

在继续之前,快速浏览一下底部导航的设计规格。

现在让我们在 Android Studio 中创建一个新项目来尝试一下。

创建新工程

第一步:从文件新建项目在 Android Studio 中创建一个新项目 File ⇒ New Project,并从模板中选择 BaseActivity。

第二步:下载此 res 文件夹并将绘图项添加到项目的 res 中。此文件夹包含底部导航项所需的绘图项。

第三步:确保你的 build.gradle 文件中有 design support library 库。

dependencies {
    implementation 'com.android.support:design:26.1.0'
}

第四步:将下面的 color、string 值添加到您的 color.xml 和 strings.xml 中。

color.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#7b4bff</color>
    <color name="colorPrimaryDark">#6539ba</color>
    <color name="colorAccent">#FF4081</color>
    <color name="bgBottomNavigation">#fe485a</color>
</resources>

strings.xml

<resources>
    <string name="app_name">Bottom Navigation</string>
    <string name="title_shop">Shop</string>
    <string name="title_gifts">Gifts</string>
    <string name="title_cart">Cart</string>
    <string name="title_profile">Profile</string>
</resources>

第五步:使用菜单文件呈现底部导航项目时,在 res 菜单文件夹下创建一个名为 navigation.xml 的新 xml。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
 
    <item
        android:id="@+id/navigation_shop"
        android:icon="@drawable/ic_store_white_24dp"
        android:title="@string/title_shop" />
 
    <item
        android:id="@+id/navigation_gifts"
        android:icon="@drawable/ic_card_giftcard_white_24dp"
        android:title="@string/title_gifts" />
 
    <item
        android:id="@+id/navigation_cart"
        android:icon="@drawable/ic_shopping_cart_white_24dp"
        android:title="@string/title_cart" />
 
    <item
        android:id="@+id/navigation_profile"
        android:icon="@drawable/ic_person_white_24dp"
        android:title="@string/title_profile" />
 
</menu>

第六步:打开 MainActivity 的布局文件,即 activity_main.xml 并添加 BottomNavigationView 小部件。在这里,我们还添加了一个 FrameLayout 来在选择导航项时加载 Fragments。

<?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/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="info.androidhive.bottomnavigation.MainActivity">
 
    <FrameLayout
        android:id="@+id/frame_container"
        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/navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="?android:attr/windowBackground"
        app:itemBackground="@color/bgBottomNavigation"
        android:foreground="?attr/selectableItemBackground"
        app:itemIconTint="@android:color/white"
        app:itemTextColor="@android:color/white"
        app:menu="@menu/navigation" />
 
</android.support.design.widget.CoordinatorLayout>

第七步:现在打开 MainActivity.java 并修改它,如下所示。

这里,当底部导航项被选中时,OnNavigationItemSelectedListener 将被调用。现在,我们只是在选择导航项时更改工具栏标题。

package info.androidhive.bottomnavigation;
 
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;
 
import info.androidhive.bottomnavigation.fragment.CartFragment;
import info.androidhive.bottomnavigation.fragment.GiftsFragment;
import info.androidhive.bottomnavigation.fragment.ProfileFragment;
import info.androidhive.bottomnavigation.fragment.StoreFragment;
import info.androidhive.bottomnavigation.helper.BottomNavigationBehavior;
 
public class MainActivity extends AppCompatActivity {
 
    private ActionBar toolbar;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        toolbar = getSupportActionBar();
 
        BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
 
        toolbar.setTitle("Shop");
    }
 
    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
            = new BottomNavigationView.OnNavigationItemSelectedListener() {
 
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            Fragment fragment;
            switch (item.getItemId()) {
                case R.id.navigation_shop:
                    toolbar.setTitle("Shop");
                    return true;
                case R.id.navigation_gifts:
                    toolbar.setTitle("My Gifts");
                    return true;
                case R.id.navigation_cart:
                    toolbar.setTitle("Cart");
                    return true;
                case R.id.navigation_profile:
                    toolbar.setTitle("Profile");
                    return true;
            }
            return false;
        }
    };
}

如果您运行该应用程序,您可以看到底部导航显示如下所示。

添加 Fragments

准备好底部导航后,让我们看看选择导航菜单项时如何切换视图。使用 Fragments 可以轻松完成此操作。

根据设计规范使用底部导航时不应该使用 ViewPager (避免使用横向运动在视图之间过渡)。

我正在创建四个名为 StoreFragment、GiftsFragment、CartFragment 和 ProfileFragment 的 Fragments。

第八步:File ⇒ New ⇒ Fragment ⇒ Fragment (Blank) 创建 Fragments 起名字为 StoreFragment.java, 同样的方式创建其他几个。

第九步:打开 MainActivity.java 并修改底部导航监听器,以加载 FrameLayout 中的 Fragments。

loadFragment() – 将 Fragment 加载到 FrameLayout 中。通过传递适当的 Fragment 实例,在 OnNavigationItemSelectedListener 回调中调用相同的方法。

package info.androidhive.bottomnavigation;
 
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;
 
import info.androidhive.bottomnavigation.fragment.CartFragment;
import info.androidhive.bottomnavigation.fragment.GiftsFragment;
import info.androidhive.bottomnavigation.fragment.ProfileFragment;
import info.androidhive.bottomnavigation.fragment.StoreFragment;
import info.androidhive.bottomnavigation.helper.BottomNavigationBehavior;
 
public class MainActivity extends AppCompatActivity {
 
    private ActionBar toolbar;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        toolbar = getSupportActionBar();
 
        // load the store fragment by default
        toolbar.setTitle("Shop");
        loadFragment(new StoreFragment());
    }
 
    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
            = new BottomNavigationView.OnNavigationItemSelectedListener() {
 
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            Fragment fragment;
            switch (item.getItemId()) {
                case R.id.navigation_shop:
                    toolbar.setTitle("Shop");
                    fragment = new StoreFragment();
                    loadFragment(fragment);
                    return true;
                case R.id.navigation_gifts:
                    toolbar.setTitle("My Gifts");
                    fragment = new GiftsFragment();
                    loadFragment(fragment);
                    return true;
                case R.id.navigation_cart:
                    toolbar.setTitle("Cart");
                    fragment = new CartFragment();
                    loadFragment(fragment);
                    return true;
                case R.id.navigation_profile:
                    toolbar.setTitle("Profile");
                    fragment = new ProfileFragment();
                    loadFragment(fragment);
                    return true;
            }
 
            return false;
        }
    };
 
    private void loadFragment(Fragment fragment) {
        // load fragment
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.replace(R.id.frame_container, fragment);
        transaction.addToBackStack(null);
        transaction.commit();
    }
 
}

现在,如果您运行该项目,则可以看到在选择导航时加载的 Fragment。

实现网格展示的 ShopFragment

现在,我们将了解如何实现第一个片段,即 ShopFragment,它以 Grid 方式显示商店商品。为了演示,我创建了一个样本 json,其中包含少量电影待售。要实现这一点,我们要做的就是获取 json 并以网格格式在RecyclerView 中显示数据。

Json 示例数据

第十步:打开 build.gradle 并添加 RecyclerView,CardView,Volley和Glide 依赖项。

dependencies {
    // RecyclerView
    compile 'com.android.support:recyclerview-v7:26.1.0'
 
    // CardView
    compile 'com.android.support:cardview-v7:26.1.0'
 
    // volley http library
    implementation 'com.android.volley:volley:1.0.0'
    implementation 'com.google.code.gson:gson:2.6.2'
 
    // glide image library
    implementation 'com.github.bumptech.glide:glide:4.3.1'
}

第十一步:创建一个名为 MyApplication.java 的类,从 Application 实现类。这是一个单例类,将在其中初始化 volley 网络请求库。

package info.androidhive.bottomnavigation.app;
 
import android.app.Application;
import android.text.TextUtils;
 
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;
 
public class MyApplication extends Application {
 
    public static final String TAG = MyApplication.class
            .getSimpleName();
 
    private RequestQueue mRequestQueue;
 
    private static MyApplication mInstance;
 
    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }
 
    public static synchronized MyApplication getInstance() {
        return mInstance;
    }
 
    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(getApplicationContext());
        }
 
        return mRequestQueue;
    }
 
    public <T> void addToRequestQueue(Request<T> req, String tag) {
        // set the default tag if tag is empty
        req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        getRequestQueue().add(req);
    }
 
    public <T> void addToRequestQueue(Request<T> req) {
        req.setTag(TAG);
        getRequestQueue().add(req);
    }
 
    public void cancelPendingRequests(Object tag) {
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(tag);
        }
    }
}

第十二步:打开 AndroidManifest.xml 并将 MyApplication 添加到 <application> 标签的 name 上。我们还要进行 INTERNET 权限申请才能进行 http 调用。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.androidhive.bottomnavigation">
 
    <uses-permission android:name="android.permission.INTERNET"/>
 
    <application
        android:name=".app.MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

第十三步:打开 StoreFragment 的布局文件,即 fragment_store.xml,然后添加以下布局代码。在这里,我们添加了 RecyclerView 组件。

<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#f1f5f7"
    tools:context="info.androidhive.bottomnavigation.fragment.StoreFragment">
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
 
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingLeft="@dimen/activity_horizontal_margin"
            android:paddingTop="10dp"
            android:text="New Release Films"
            android:textColor="#111"
            android:textSize="16dp" />
 
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:clipToPadding="false"
            android:scrollbars="vertical" />
    </LinearLayout>
</android.support.v4.widget.NestedScrollView>

第十四步:在 res 布局下创建一个名为 store_item_row.xml 的 xml 布局。这个布局文件将被用在 Recyclerview 适配器类中来呈现单个项目。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
 
    <android.support.v7.widget.CardView
        android:id="@+id/card_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:layout_margin="@dimen/card_margin"
        android:clickable="true"
        android:elevation="3dp"
        android:foreground="?attr/selectableItemBackground"
        card_view:cardCornerRadius="@dimen/card_album_radius">
 
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
 
            <ImageView
                android:id="@+id/thumbnail"
                android:layout_width="match_parent"
                android:layout_height="@dimen/album_cover_height"
                android:background="?attr/selectableItemBackgroundBorderless"
                android:clickable="true"
                android:scaleType="fitXY" />
 
            <TextView
                android:id="@+id/title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/thumbnail"
                android:lines="2"
                android:paddingLeft="@dimen/album_title_padding"
                android:paddingRight="@dimen/album_title_padding"
                android:paddingTop="@dimen/album_title_padding"
                android:textColor="#111"
                android:textSize="11dp" />
 
            <TextView
                android:id="@+id/price"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/title"
                android:layout_marginRight="10dp"
                android:gravity="right"
                android:paddingBottom="@dimen/songs_count_padding_bottom"
                android:textColor="@color/colorAccent"
                android:textSize="11dp" />
 
        </RelativeLayout>
 
    </android.support.v7.widget.CardView>
</LinearLayout>

第十五步:创建一个名为 Movie.java 的类。这个 POJO 类在解析 json 时非常有用。

package info.androidhive.bottomnavigation;
 
public class Movie {
    String title;
    String image;
    String price;
 
    public String getTitle() {
        return title;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }
 
    public String getImage() {
        return image;
    }
 
    public void setImage(String image) {
        this.image = image;
    }
 
    public String getPrice() {
        return price;
    }
 
    public void setPrice(String price) {
        this.price = price;
    }
}

第十六步:现在打开 StoreFragment.java 并添加以下代码。为简单起见,在相同的代码 Fragment 中包含了 Recyclerview 适配器类 StoreAdapter。

fetchStoreItems() - 方法使用 Volley 获取 movies json 并使用 Gson 序列化它。

StoreAdapter - 渲染电影列表的适配器类。

package info.androidhive.bottomnavigation.fragment;
 
 
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
 
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
import com.bumptech.glide.Glide;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
 
import org.json.JSONArray;
 
import java.util.ArrayList;
import java.util.List;
 
import info.androidhive.bottomnavigation.Movie;
import info.androidhive.bottomnavigation.app.MyApplication;
import info.androidhive.bottomnavigation.R;
 
public class StoreFragment extends Fragment {
 
    private static final String TAG = StoreFragment.class.getSimpleName();
    private static final String URL = "https://api.androidhive.info/json/movies_2017.json";
 
    private RecyclerView recyclerView;
    private List<Movie> movieList;
    private StoreAdapter mAdapter;
 
    public StoreFragment() {
        // Required empty public constructor
    }
 
    public static StoreFragment newInstance(String param1, String param2) {
        StoreFragment fragment = new StoreFragment();
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_store, container, false);
 
        recyclerView = view.findViewById(R.id.recycler_view);
        movieList = new ArrayList<>();
        mAdapter = new StoreAdapter(getActivity(), movieList);
 
        RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(getActivity(), 3);
        recyclerView.setLayoutManager(mLayoutManager);
        recyclerView.addItemDecoration(new GridSpacingItemDecoration(2, dpToPx(8), true));
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.setAdapter(mAdapter);
        recyclerView.setNestedScrollingEnabled(false);
 
        fetchStoreItems();
 
        return view;
    }
 
    private void fetchStoreItems() {
        JsonArrayRequest request = new JsonArrayRequest(URL,
                new Response.Listener<JSONArray>() {
                    @Override
                    public void onResponse(JSONArray response) {
                        if (response == null) {
                            Toast.makeText(getActivity(), 
                                "Couldn't fetch the store items! Pleas try again.", 
                                Toast.LENGTH_LONG).show();
                            return;
                        }
 
                        List<Movie> items = new Gson().fromJson(response.toString(), new TypeToken<List<Movie>>() {
                        }.getType());
 
                        movieList.clear();
                        movieList.addAll(items);
 
                        // refreshing recycler view
                        mAdapter.notifyDataSetChanged();
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // error in getting json
                Log.e(TAG, "Error: " + error.getMessage());
                Toast.makeText(getActivity(), "Error: " + error.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
 
        MyApplication.getInstance().addToRequestQueue(request);
    }
 
    public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
 
        private int spanCount;
        private int spacing;
        private boolean includeEdge;
 
        public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
            this.spanCount = spanCount;
            this.spacing = spacing;
            this.includeEdge = includeEdge;
        }
 
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            int position = parent.getChildAdapterPosition(view); // item position
            int column = position % spanCount; // item column
 
            if (includeEdge) {
                // spacing - column * ((1f / spanCount) * spacing)
                outRect.left = spacing - column * spacing / spanCount; 

                // (column + 1) * ((1f / spanCount) * spacing)
                outRect.right = (column + 1) * spacing / spanCount; 
 
                if (position < spanCount) { // top edge
                    outRect.top = spacing;
                }
                outRect.bottom = spacing; // item bottom
            } else {
                // column * ((1f / spanCount) * spacing)
                outRect.left = column * spacing / spanCount; 

                // spacing - (column + 1) * ((1f /    spanCount) * spacing)
                outRect.right = spacing - (column + 1) * spacing / spanCount; 
                if (position >= spanCount) {
                    outRect.top = spacing; // item top
                }
            }
        }
    }
 
    /**
     * Converting dp to pixel
     */
    private int dpToPx(int dp) {
        Resources r = getResources();
        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()));
    }
 
    class StoreAdapter extends RecyclerView.Adapter<StoreAdapter.MyViewHolder> {
        private Context context;
        private List<Movie> movieList;
 
        public class MyViewHolder extends RecyclerView.ViewHolder {
            public TextView name, price;
            public ImageView thumbnail;
 
            public MyViewHolder(View view) {
                super(view);
                name = view.findViewById(R.id.title);
                price = view.findViewById(R.id.price);
                thumbnail = view.findViewById(R.id.thumbnail);
            }
        }
 
 
        public StoreAdapter(Context context, List<Movie> movieList) {
            this.context = context;
            this.movieList = movieList;
        }
 
        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View itemView = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.store_item_row, parent, false);
 
            return new MyViewHolder(itemView);
        }
 
        @Override
        public void onBindViewHolder(MyViewHolder holder, final int position) {
            final Movie movie = movieList.get(position);
            holder.name.setText(movie.getTitle());
            holder.price.setText(movie.getPrice());
 
            Glide.with(context)
                    .load(movie.getImage())
                    .into(holder.thumbnail);
        }
 
        @Override
        public int getItemCount() {
            return movieList.size();
        }
    }
}

现在,如果您运行该应用程序,则可以看到 ShopFragment 以网格方式显示电影。同样,您也可以实现其他 Fragment。

隐藏底部的滚动导航

根据设计规范,当内容滚动时,底部的导航必须隐藏起来,为屏幕上的内容提供更多的空间。为了实现这一点,我们需要将 BottomNavigationBehavior 附加到 Bottom Navigation。

第十七步:使用下面的代码创建一个名为 BottomNavigationBehavior.java 的类。

package info.androidhive.bottomnavigation.helper;
 
import android.content.Context;
import android.support.design.widget.BottomNavigationView;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
 
public class BottomNavigationBehavior extends CoordinatorLayout.Behavior<BottomNavigationView> {
 
    public BottomNavigationBehavior() {
        super();
    }
 
    public BottomNavigationBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
 
    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, BottomNavigationView child, View dependency) {
        boolean dependsOn = dependency instanceof FrameLayout;
        return dependsOn;
    }
 
    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, 
            BottomNavigationView child, View directTargetChild, View target, int nestedScrollAxes) {
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
    }
 
    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, 
            BottomNavigationView child, View target, int dx, int dy, int[] consumed) {
        if (dy < 0) {
            showBottomNavigationView(child);
        } else if (dy > 0) {
            hideBottomNavigationView(child);
        }
    }
 
    private void hideBottomNavigationView(BottomNavigationView view) {
        view.animate().translationY(view.getHeight());
    }
 
    private void showBottomNavigationView(BottomNavigationView view) {
        view.animate().translationY(0);
    }
}

第十八步:在 MainActivity.java 中使用 setBehavior() 添加 BottomNavigationBehavior,如下所示。

public class MainActivity extends AppCompatActivity {
 
    private ActionBar toolbar;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
 
        // attaching bottom sheet behaviour - hide / show on scroll
        CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) navigation.getLayoutParams();
        layoutParams.setBehavior(new BottomNavigationBehavior());
 
        // load the store fragment by default
        // ..
    }
}

现在,如果你测试这个应用程序,你可以看到当滚动应用程序内容时,底部的导航栏会向下滑动。