结合TabLayout 、ViewPager 、 Fragment 实现顶部导航栏,最实用!!!

     说明:因为我习惯实用DataBinding,所以本文使用了DataBinding 的知识,如果对 DataBinding 还没有一点了解的强烈建议大家一定先去了解一下 DataBinding 相关的知识Android DataBinding 详解)。

下面我们开始一步步来实现:

1.首先我们先来创建所需要的 Fragement 以及相对应的布局文件,这里我们拿首页 HomeFragment 来做示例:

首先创建 fragment_home.xml 布局文件如下:




    

        

    

     这里非常简单,一个线性布局里面放一个 TextView,想必大家一看就明白,只是要注意最外层布局是 标签,这就是刚才提到的 DataBinding 需要的,和我们平时的布局不太一样的一点

接下来创建 HomeFragment 类:

package com.example.qiudengjiao.tablayout.Module.home;

import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.qiudengjiao.tablayout.Base.BaseFragment;
import com.example.qiudengjiao.tablayout.R;
import com.example.qiudengjiao.tablayout.databinding.FragmentHomeBinding;

/**
 * 主界面 - 首页Fragment
 * Created by qiudengjiao on 2017/5/6.
 */

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

        FragmentHomeBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false);
        
        return binding.getRoot();
    }
}

     我们来简单看一下上面的这段代码,和我们平时写的其实差不太多,使用 DataBindingUtil 调用 inflate() 方法来加载我们刚写好的布局,返回一个 FramentHomeBinding 对象,这个对象是自动生成的,这个对象的生成和布局文件的名字是有关系的,生成规则就是布局文件的名字加 Binding,更详细的大家可以去看我关于 DataBinding 的博文,这里不再展开详细描述,再就是  return binding.getRoot(),这句代码就是返回上面绑定的布局文件,到这里我们的首页 HomeFragment 就创建完成了,剩下了热卖、购物车、分类、我的依次类推,我们一一创建完成,这里不再描述,如下:



    这样我们所需要的所有 Fragment 就全部创建完成,需要多少个 Tab 就创建多少个相对应的 Fragment,这个大家根据自己的项目来定

接下来我们来创建主布局文件 activity_main.xml 代码如下:


这里需要注意的是需要先在 app/build.gradle 中添加如下依赖,如果你的项目中还没有添加的话:

compile 'com.android.support:design:25.1.0'  





    

        

        

        

        


        
    

       和上面一样,最外层是 layout 布局,接着里面嵌套了一个线性布局,线性布局里面主要放了一个 ViewPager,一个 TabLayout,也比较简单,接下来就是定义适配器 Adapter 类,这里我们暂且命名为 MainTabAdapter,代码如下:

/**
 * 适配器
 * Created by qiudengjiao on 2017/5/6.
 */


public class MainTabAdapter extends FragmentPagerAdapter {


    private MainActivity mContext;


    private HomeFragment homeFragment;
    private HotFragment hotFragment;
    private CategoryFragment categoryFragment;
    private CartFragment cartFragment;
    private MineFragment mineFragment;


    public MainTabAdapter(MainActivity mainActivity) {
        super(mainActivity.getSupportFragmentManager());
        this.mContext = mainActivity;


        //初始化Fragment
        homeFragment = new HomeFragment();
        hotFragment = new HotFragment();
        categoryFragment = new CategoryFragment();
        cartFragment = new CartFragment();
        mineFragment = new MineFragment();
    }


    @Override
    public Fragment getItem(int position) {
        if (position == 0) {
            return homeFragment;
        } else if (position == 1) {
            return hotFragment;
        } else if (position == 2) {
            return categoryFragment;
        } else if (position == 3) {
            return cartFragment;
        } else if (position == 4) {
            return mineFragment;
        }
        return null;
    }


    @Override
    public int getCount() {
        return 5;
    }
}

     这里我们继承 FragmentPagerAdapter,并且在构造函数里初始化了我们刚才准备好的 Fragment,还实现了它的 getItem() 和 getCount() 方法,在 getItem() 方法中返回相应的 Fragment,getCount() 方法中返回相对应的个数


接下来我们开始来定义 MainAcitivity,代码如下:

package com.example.qiudengjiao.tablayout;

import android.databinding.DataBindingUtil;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import com.example.qiudengjiao.tablayout.Adapter.MainTabAdapter;
import com.example.qiudengjiao.tablayout.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;

    private FragmentPagerAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        //初始化适配器
        mAdapter = new MainTabAdapter(this);

        binding.viewPager.setAdapter(mAdapter);


        //将TabLayout和ViewPager关联起来
        binding.tabLayout.setupWithViewPager(binding.viewPager);

        binding.viewPager.setOffscreenPageLimit(5);


        initTab();
    }

    /**
     * 设置添加Tab
     */
    private void initTab() {

        binding.tabLayout.getTabAt(0).setCustomView(R.layout.tab_home);
        binding.tabLayout.getTabAt(1).setCustomView(R.layout.tab_hot);
        binding.tabLayout.getTabAt(2).setCustomView(R.layout.tab_category);
        binding.tabLayout.getTabAt(3).setCustomView(R.layout.tab_cart);
        binding.tabLayout.getTabAt(4).setCustomView(R.layout.tab_mine);

        //默认选中的Tab
        binding.tabLayout.getTabAt(0).getCustomView().setSelected(true);

    }

}

     这里的代码其实也挺干净简单,首先初始化适配器,并通过 setupWithViewPager() 方法将 TabLayout 和 ViewPager 关联起来,然后初始化 Tab,并通过 getTabAt() 方法返回指定的 Tab 选项,然后通过 setCustomView() 把自定义的布局设置到此 Tab 选项卡上,注意这里的布局是我们自己定义的,下面会讲解,然后通过 setSelected() 方法来设置默认选中的 Tab 选项卡,接下来我们来看一下我们自定义的布局,还是拿一个 tab_home.xml 来做演示,代码如下:



    

    


 可以看到在线性布局里面包含了一个 ImageView 和一个 TextView 这个 ImageView 就是我们地步导航栏 Tab 选项卡中的图标,TextView 就是相对应的文字,这里需要注意的就是需要用选择器 selector 的形式来设置图片和文字,代码如下:

图片选择器:selector_tab_home.xml








文字选择器:selector_tab_text.xml,需要注意的是这里文字选择器只需要一个就可以了,因为不管那个 Tab 选项卡的文字颜色变化都是一样的



    
    

下的图片选择器请大家自行编写,写完如下:



   到这里我们的底部导航栏就完成了,实现效果就是我们文章刚开始贴出的效果,到这里还有一个问题,那就是我们的底部导航栏是可以滑动的,但往往在实际项目中是不能滑动的,这个也好解决,就是我们需要去自定义一个 ViewPager,把滑动功能禁止掉就可以了,下面贴上自定义的 ViewPager,代码如下:

  

/**
 * 不可滑动的ViewPager
 * Created by qiudengjiao on 2017/1/20.
 */


public class NoScrollViewPager extends ViewPager {




    public boolean canScroll = false;


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


    public NoScrollViewPager(Context context) {
        super(context);
    }
    


    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return canScroll && super.onTouchEvent(ev);
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return canScroll && super.onInterceptTouchEvent(ev);
    }


    @Override
    public void setCurrentItem(int item) {
        setCurrentItem(item, false);
    }
}


        这里我们自定义了自己的 NoScrollViewPager,继承 ViewPager 并从写了 onTouchEvent() 和 onInterceptTouchEvent() 方法,这两个方法的返回值都是 boolean 类型的,只需要改为 false,ViewPager 就不会消耗掉手指的滑动事件了,也就是说就不会再传递给上层View 去处理该滑动事件了,如果大家想让 ViewPager 从新滑动,只需要把 pulic boolean canSoroll = false 改为 ture 即可,如果大家想彻底的搞明白,那么就需要去搞清楚 View 的事件分发,这里就不详细介绍了

接下来就是在 activity_main.xml 布局文件中去引用我们自己定义的 ViewPager,代码如下:




    

        

        

        

        


        
    


到这里我们就把 ViewPager 左右滑动禁止了,底部导航栏也就算是彻底完成了!

你可能感兴趣的:(TabLayout)