BottomNavigationView+ViewPager实现底部导航栏

前言: 前面写过一篇FragmentTabHost+FrameLayout实现底部导航栏 公司原来一直这个套路来处理底部导航栏和显示页面的切换,真的很好用。但是自从发现BottomNavigationView这个控件之后,感觉BottomNavigationView+ViewPager实现底部导航栏这个模式更简单而且效果更酷。写个小demo展示一下,下面先看一下效果图:
BottomNavigationView+ViewPager实现底部导航栏_第1张图片—>BottomNavigationView+ViewPager实现底部导航栏_第2张图片

首先: 来看一下整体布局代码:
activity_main.xml

"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.blueskygrid.test1.MainActivity">

    <com.blueskygrid.test1.widget.NoSlidingViewPaper
        android:id="@+id/vp_main_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">
    com.blueskygrid.test1.widget.NoSlidingViewPaper>

    .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:menu="@menu/navigation" />

代码很简单,总体分为两部分,第一部分,NoSlidingViewPaper显示主体内容部分,继承Viewpager屏蔽了ViewPager左右滑动,代码很简单,代码如下:
NoSlidingViewPaper.java

public class NoSlidingViewPaper extends ViewPager {
    public NoSlidingViewPaper(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public NoSlidingViewPaper(Context context) {
        super(context);
    }
    /*
     * 表示把滑动事件传递给下一个view
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent arg0) {
        return false;
    }
    /*
     * 可以啥都不做
     */
    public boolean onTouchEvent(MotionEvent arg0) {
        return false;
    }
}

第二部分,BottomNavigationView就是底部的导航栏了,除了app:menu=”@menu/navigation”这个属性设置以外,其他的大家都知道。这个属性就是给导航栏设置菜单项,这个和我们在标题栏上放设置菜单项的原理是一样的。在meau文件夹下(如果你的工程没有这个文件夹,就建一个)新建navigation.xml,在里面写要展示的菜单项,先看一下代码:
navigation.xml


<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/navigation_home"
        android:icon="@drawable/ic_me_normal"
        android:title="@string/title_home" />

    <item
        android:id="@+id/navigation_message"
        android:icon="@drawable/ic_message_normal"
        android:title="@string/title_message" />

    <item
        android:id="@+id/navigation_publish"
        android:icon="@drawable/ic_publish_normal"
        android:title="@string/title_publish" />
menu>

可以看到,我建立了三个菜单项,id这个大家知道,是唯一标识,为了处理点击事件做准备,icon代表菜单项图标,title菜单项文字。注意:这里的icon用的是矢量图 ,不怎么了解矢量图的同学可以百度先了解一下,下片文章,我会写一下我用位图怎么转化为矢量图的。如果你需要我的矢量图,可以到文章最下面下载。

接下来, 我们先来看一下逻辑代码:

public class MainActivity extends AppCompatActivity {

    private NoSlidingViewPaper mViewPager;

    //底部菜单栏各个菜单项的点击事件处理
    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
            = new BottomNavigationView.OnNavigationItemSelectedListener() {

        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            switch (item.getItemId()) {
                case R.id.navigation_home://主页
                    mViewPager.setCurrentItem(0);
                    return true;
                case R.id.navigation_message://信息
                    mViewPager.setCurrentItem(1);
                    return true;
                case R.id.navigation_publish://发布
                    mViewPager.setCurrentItem(2);
                    return true;
            }
            return false;
        }

    };

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

        /*初始化显示内容*/
        mViewPager = (NoSlidingViewPaper) findViewById(R.id.vp_main_container);
        final ArrayList fgLists = new ArrayList<>(3);
        fgLists.add(new HomeFragment());
        fgLists.add(new MessageFragment());
        fgLists.add(new PublishFragment());
        FragmentPagerAdapter mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                return fgLists.get(position);
            }

            @Override
            public int getCount() {
                return fgLists.size();
            }
        };
        mViewPager.setAdapter(mAdapter);
        mViewPager.setOffscreenPageLimit(2); //预加载剩下两页

        BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
        /*给底部导航栏菜单项添加点击事件*/
        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
    }
}

可以看出逻辑代码很少,很容易看懂,点击菜单跳转到相应的Fragement,至于菜单项选中和变色,我们都不用管,BottomNavigationView都已经帮我们处理好了,如果我们想修改菜单项选中的颜色,我们可以通过改变styles.xml文件中BaseTheme的colorPrimary的值。到这里其实已经可以实现前面图1的效果了。因为Viewpager有预加载下一页这个模式,我这里是设置预加载了两页。这三个页面都有网络请求,那进入app耗时长,体验效果很差

所以,下面我们用懒加载来处理这个问题, 先来看一下代码:
BaseFragment.java

public abstract class BaseFragement extends Fragment {

    protected View mView;
    protected boolean isViewInitiated; //当前页面是否初始化
    protected boolean isVisibleToUser; //当前页面是否显示
    protected boolean isDataRequested; //是否已经请求了数据
    protected Context mContext;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        mContext = getContext();
        mView = inflater.inflate(getLayoutId(), null);
        isViewInitiated = true;
        initView();
        prepareGetData();
        return mView;
    }

    /*初始化页面布局和数据*/
    protected abstract void initView();
    /*布局*/
    public abstract int getLayoutId();
    /*服务器获取数据*/
    protected abstract void getDataFromServer();

    /**
     * 当前页面是否展示
     * @param isVisibleToUser 显示为true, 不显示为false
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        this.isVisibleToUser = isVisibleToUser;
        prepareGetData();
    }

    /**
     * 如果只想第一次进入该页面请求数据,return prepareGetData(false)
     * 如果想每次进入该页面就请求数据,return prepareGetData(true)
     * @return
     */
    private boolean prepareGetData(){
        return prepareGetData(false);
    }

    /**
     * 判断是否从服务器器获取数据
     * @param isforceUpdate 强制更新的标记
     * @return
     */
    protected boolean prepareGetData(boolean isforceUpdate) {
        if(isVisibleToUser && isViewInitiated && (!isDataRequested || isforceUpdate)){
            /*从服务器获取数据*/
            getDataFromServer();
            isDataRequested = true;
            return true;
        }
        return false;
    }
}

HomeFragment.java

public class HomeFragment extends BaseFragement{

    @Override
    protected void initView() {

    }
    @Override
    public int getLayoutId() {
        return R.layout.fragment_home;
    }
    @Override
    protected void getDataFromServer() {
        Toast.makeText(mContext, "HomeFragment页面请求数据了", Toast.LENGTH_SHORT).show();
    }
}

主要逻辑看BaseFragment,可以结合我的注释看,主要有一个不常用的方法setUserVisibleHint(boolean isVisibleToUser) 这个方法可以处理判断某个页面是否显示。
文章到这里已经结束了,有不对的地方,欢迎指正^_^,另一篇文章链接:BottomNavigationView3个菜单项以上时去除动画效果

demo下载地址

你可能感兴趣的:(viewpager,导航栏,2016-android总结)