这是我们 Material Design 系列的第四篇分享了,对 Material Design 还不是太清楚的可以先看前几篇博文大概的了解一下,今天我们主要通过实现顶部和底部导航栏的功能来了解又一个 Material Design 的控件 TabLayout 的使用,在移动应用开发中,由于屏膜大小的限制,使得顶部、底部 Tab 导航栏的使用非常的广泛,相信大家在实际开发过程中也是经常遇到,以前可以通过 RadioGroup,FragmentTabHost 以及后来的 Bottom Navigation 等方法来实现,现在我们可以使用 Design Support library 库的 TabLayout 来实现了
一、底部导航栏
我们先上效果图吧
上面就是我们的效果图,接下来我们来通过代码一步步实现上面的效果,这里我使用了一点 DataBinding 的知识,如果对 DataBinding 还没有一点了解的可以去看我以前的博文简单的了解一下(这里强烈的建议大家一定去了解一下 DataBinding 相关的知识),好了开始代码演绎吧
Android DataBinding 详解
1.首先我们先来创建所需要的 Fragement 以及相对应的布局文件,这里我们拿首页 HomeFragment 来做示例:
首先创建 fragment_home.xml 布局文件如下:
这里非常简单,一个线性布局里面放一个 TextView,想必大家一看就明白,只是要注意最外层布局是
接下来创建 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();
}
}
这样我们所需要的所有 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 来做演示,代码如下:
图片选择器:selector_tab_home.xml
剩下的图片选择器请大家自行编写,写完如下:
到这里我们的底部导航栏就完成了,实现效果就是我们文章刚开始贴出的效果,到这里还有一个问题,那就是我们的底部导航栏是可以滑动的,但往往在实际项目中是不能滑动的,这个也好解决,就是我们需要去自定义一个 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);
}
}
接下来就是在 activity_main.xml 布局文件中去引用我们自己定义的 ViewPager,代码如下:
二、顶部导航栏
到这里大家想必顶部导航栏心里也就有数了,这里我们还是简单的来看一下,效果图如下:
接下来我们就上代码,这里我们首先创建顶部 Tab 对应的 Fragment,代码就不写了,和上面的是一样的,接下来我们来看 activity_top_layout.xml 布局文件:
等等,属性就简单介绍这些,更多的项目中用到的大家可以自己尝试,这里就不一一全部列举了
接下来我们就来写适配器了,这里我们命名为 TopAdapter,相关代码如下:
/**
* 顶部导航栏 Adapter
* Created by qiudengjiao on 2017/5/8.
*/
public class TopAdapter extends FragmentPagerAdapter {
//Fragment列表
private List mFragment;
//Tab名列表
private List mTitle;
public TopAdapter(FragmentManager fm, List fragments, List titles) {
super(fm);
this.mFragment = fragments;
this.mTitle = titles;
}
@Override
public Fragment getItem(int position) {
return mFragment.get(position);
}
@Override
public int getCount() {
return mTitle.size();
}
//此方法用来显示Tab上的名字
@Override
public CharSequence getPageTitle(int position) {
return mTitle.get(position);
}
}
package com.example.qiudengjiao.tablayout.top;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import com.example.qiudengjiao.tablayout.Adapter.TopAdapter;
import com.example.qiudengjiao.tablayout.Base.BaseActivity;
import com.example.qiudengjiao.tablayout.R;
import com.example.qiudengjiao.tablayout.databinding.ActivityTopLayoutBinding;
import java.util.ArrayList;
import java.util.List;
/**
* 顶部导航栏
* Created by qiudengjiao on 2017/5/8.
*/
public class TopLayoutActivity extends BaseActivity {
private FragmentPagerAdapter mAdapter;
private List mFragment;
private List mTitle;
private ActivityTopLayoutBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
//隐藏掉整个ActionBar
getSupportActionBar().hide();
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_top_layout);
initTabFragment();
}
private void initTabFragment() {
//初始化Fragment
Fragment1 fragment1 = new Fragment1();
Fragment2 fragment2 = new Fragment2();
Fragment3 fragment3 = new Fragment3();
//将Fragment装进列表中
mFragment = new ArrayList<>();
mFragment.add(fragment1);
mFragment.add(fragment2);
mFragment.add(fragment3);
//将名称添加daoTab列表
mTitle = new ArrayList<>();
mTitle.add("Tab1");
mTitle.add("Tab2");
mTitle.add("Tab3");
//为TabLayout添加Tab名称
binding.topTabLayout.addTab(binding.topTabLayout.newTab().setText(mTitle.get(0)));
binding.topTabLayout.addTab(binding.topTabLayout.newTab().setText(mTitle.get(1)));
binding.topTabLayout.addTab(binding.topTabLayout.newTab().setText(mTitle.get(2)));
mAdapter = new TopAdapter(this.getSupportFragmentManager(), mFragment, mTitle);
//ViewPager加载Adapter
binding.topViewPager.setAdapter(mAdapter);
//TabLayout加载ViewPager
binding.topTabLayout.setupWithViewPager(binding.topViewPager);
}
}
到这里我们项目中常用的的底部和顶部导航栏就都实现了,是不是觉得比以前的实现方法简单了许多
源码Demo:点击打开链接
谢谢阅读,如有问题请指出