前两次我们说了MaterialDesign中,Toolbar,DrawerLayout和NavigationView组成的Activity界面,下面我们来说说TabLayout,ViewPager,Fragment和RecyclerView组成的带有标签的界面,先来看看效果:
如图,Toolbar下多了一行标签,点击标签就会跳到对应的页面。我们先来说说每个控件负责显示什么以及它的范围:
1.TabLayout:负责标签行,区域就在Toolbar下的蓝色区域。
2.ViewPager:负责加载动态加载每个标签对应的Fragment。区域是TabLayout下所有的区域。
3.Fragment:负责加载对应的RecyclerView。由ViewPager加载到Activity中。区域也是TabLayout下 所有的区域。
4.RecyclerView:负责显示数据。图中的图片加字符串,就是由RecyclerView负责显示以及加载的。
在代码中,TabLayout和ViewPager会创建联系,ViewPager和Fragment会创建联系,Fragment和RecyclerView会创建联系。
总结就是:TabLayout会随着ViewPager的滑动,而切换标签,同样,ViewPager会随着TabLayout标签的选择而滑动到对应的页面。ViewPager会随着标签的不同加载对应的Fragment,而Fragment中则会加载RecyclerView。下面我们来看看代码。先来看看布局文件我们接着在activity_main的基础上进行修改:
<android.support.v4.widget.DrawerLayout
>
<LinearLayout
>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
/>
<android.support.design.widget.TabLayout
android:id="@+id/main_tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabTextColor="#fff"
app:tabMode="scrollable"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/main_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
<android.support.design.widget.NavigationView
/>
</android.support.v4.widget.DrawerLayout>
方便起见,我把前面定义过的控件都只留下标签,里面的属性都删减了,我们重点要看的是TabLayout和ViewPager还有一个AppBarLayout的部分。
1.AppBarLayout:design包下的控件,其实就是一个垂直方向的LinearLayout,但是其内部做了很多滚动事件的封装。而且包含了一些MaterialDesign的设计理念。这节我们不会说到它的具体作用,暂且先把她理解为一个垂直方向的LinearLayout,其作用就是将ToolBar和TabLayout包裹成一个整体。
2.TabLayout:design包下的控件,作用上面已经说过了,我们主要来看看它的属性app:tabMode,这个属性有两个值可选,分别是scrollable和fixed。这里我们指定的是scrollable,顾名思义,就是可滑动的,那么另外的fixed就是固定的。这个属性是用来控制TabLayout的标签是否可以滑动,当我们的标签比较多时就选择scrollable,比较少时就选择fixed。不同之处我们来看看图,如下:
上面的状态时我们将tabMode的属性值改成fixed,可以看到标签栏部分的标签显示不完整,因为,当选择fixed即是不可滑动,那么TabLayout又要将所有标签显示出来,就会出现图中的情况,标签都被压缩的不成样子,所以,标签很多的时候,我们需要把该属性的值设置为scrollable。
3.ViewPager:ViewPager就没啥特别的属性了,只是要注意,它并不是AppBarLayout的子控件,他在TabLayout的外面。
ok,布局文件就是这样,并没有什么复杂的,我们接下来看看代码,在这之前我们需要准备一下Fragment和RecyclerView,这里我们只贴Fragment的代码,RecyclerView在前面的博文中已经很详细的说过了,如果有疑问可以去前面的博文看看。(注意,这里的RecyclerView显示的数据我在定义RecyclerView的布局文件的时候都已经直接指定了(ImageView指定了src,TextView指定了text)。所以里面的每一个子项的数据都是一样的)。下面我们来看看Fragment的代码:
public class RecyclerViewFragment extends Fragment {
private RecyclerView view;
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
view.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayout.VERTICAL,false));
view.setAdapter(new MyAdapter());
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view =(RecyclerView) inflater.inflate(R.layout.layout,container,false);
return view;
}
}
如上,定义Fragment需要继承Fragment - -,注意继承的Fragment是support包下的。这里我们重写了两个方法,分别是onCreateView和onActivityCreate。我们来看看这两个方法的作用:
1.onCreateView:看代码中,我们可以知道这个方法中有一个参数:LayoutInflater,那么很明显,这个方法一般是用来加载Fragment布局的。前面说过,我们的Fragment中就只有一个RecyclerView,那么代码中加载的布局文件R.layout.layout也就只是一个RecyclerView。
2.onActivityCreate:这个方法,在确保与Fragment关联的Activity被创建时调用,在这个方法里,我们为RecyclerView设置了LinearLayoutManager和Adapter,也就是在这,我们为Fragment加载了RecyclerView。
Fragment我们定义好了,接着我们来看看MainActivity中的代码:
public class MainActivity extends AppCompatActivity {
*****************省略上两节的代码*******************
private TabLayout mTabLayout;
private ViewPager mViewPager;
private List<String> titleList;
private List<RecyclerViewFragment> mFragmentList;
private void initView() {
//找到控件
mTabLayout = findViewById(R.id.main_tab_layout);
mViewPager = findViewById(R.id.main_view_pager);
initTab();
}
private void initTab() {
//这里创建两个List一个用来存储每个Tab的标题,一个用来存储Fragment
titleList = new ArrayList<>();
mFragmentList = new ArrayList<>();
//为titleList添加数据
titleList.add("时事");
titleList.add("国内");
titleList.add("国际");
titleList.add("时政");
titleList.add("体育");
titleList.add("娱乐");
titleList.add("头条");
titleList.add("社会");
titleList.add("时事");
titleList.add("国内");
titleList.add("国际");
titleList.add("时政");
titleList.add("体育");
titleList.add("娱乐");
titleList.add("头条");
titleList.add("社会");
//遍历titleList中的数据,并创建对应数量的Tab添加到TabLayout中
for(int i = 0;i<titleList.size();i++){
//创建Tab
TabLayout.Tab tab = mTabLayout.newTab();
//为Tab添加标题
tab.setText(titleList.get(i));
//将定义好的Tab添加到TabLayout中
mTabLayout.addTab(tab);
}
RecyclerViewFragment fragment;
//这里创建我们定义好的RecyclerViewFragment,并添加到mFragmentList中
for (int i = 0;i<titleList.size();i++){
fragment = new RecyclerViewFragment();
mFragmentList.add(fragment);
}
//注释1 这是我们自己创建的 FragmentStatePagerAdapter
MyFragmentAdapter fragmentAdapter = new MyFragmentAdapter(getSupportFragmentManager(),titleList,mFragmentList);
//将定义好的MyFragmentAdapter和viewPager关联 注释2
mViewPager.setAdapter(fragmentAdapter);
//这里关联TabLayout和ViewPager 注释3
mTabLayout.setupWithViewPager(mViewPager);
}
}
接着我们贴出MyFragmentAdapter的代码,如下:
public class MyFragmentAdapter extends FragmentStatePagerAdapter {
private List<String> mTitleList;
private List<RecyclerViewFragment> mFragmentList;
public MyFragmentAdapter(FragmentManager fm, List<String> titleList,List<RecyclerViewFragment> fragmentList) {
super(fm);
mTitleList = titleList;
mFragmentList = fragmentList;
}
@Override
public CharSequence getPageTitle(int position) {
return mTitleList.get(position);
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
}
如上,我们先来说说MyFragmentAdapter这个类,这个类是继承自support.v4包FragmentStatePagerAdapter的。这里重写了三个普通方法和一个构造方法,我们先来看看构造方法。
这个构造方法有三个参数,第一个FragmentManager是固定的,后面两个List类型的参数是我们自己定义了,用来获取数据的。
我们再来看看三个普通方法,分别是getPageTitle,getItem和getCount:
1.getPageTitle:返回值类型是CharSequence,也就是也就是字符串。这里我们根据参数position返回mTitleList中对应的值。
2.getItem:返回值类型是Fragment,很明显这里我们只要根据参数的position返回mFragmentList中对应的RecyclerViewFragment即可。
3.getCount:返回值类型是int,就是返回子项的数量,随便返回一个List的size就可以。
ok,MyFragmentAdapter很简单,我们回到MainActivity代码中,来看看代码中标记的3个注释:
1.注释1:创建MyFragmentAdapter,将我们定义的titleList和mFragmentList传进去,需要注意的是,这里我们用的Fragment是继承support库的,所以获取的FragmentManager需要使用getSupportFragmentManager这个方法。
2.注释2:将创建的MyFragmentAdapter和viewPager关联,使ViewPager能获取对应position下的title和fragment。
3.注释3:将ViewPager和Tablayout关联起来,使ViewPager能响应TabLayout中Tab的切换,从而切换Fragment显示Tab标签对应的数据。同样,使TabLayout能响应Viewpager的滑动,从而更换Tab标签。
ok,这次就说那么多,下次我们说说Toolbar的折叠。
本人菜鸟,不对之处,请各路大神指正。