使用FragmentTabHost+TabLayout+ViewPager实现双层嵌套Tab

大多数应用程序都会在底部使用3~5个Tab对应用程序的主要功能进行划分,对于一些信息量非常大的应用程序,还需要在每个Tab下继续划分子Tab对信息进行分类显示.

本文实现采用FragmentTabHost+TabLayout+ViewPager实现双层嵌套Tab,实现原理如下:

      第一层Tab:FragmentTabHost + Fragment;

      第二层Tab:在第一层的Fragment中使用TabLayout和ViewPager实现.

第一层Tab实现:

1.布局文件activity_main.xml如下:

复制代码
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <android.support.v4.app.FragmentTabHost android:id="@android:id/tabhost"
 3     xmlns:android="http://schemas.android.com/apk/res/android"
 4     android:layout_width="match_parent"
 5     android:layout_height="match_parent">
 6 
 7     <LinearLayout
 8         android:layout_width="match_parent"
 9         android:layout_height="match_parent"
10         android:orientation="vertical">
11         <FrameLayout
12             android:id="@android:id/tabcontent"
13             android:layout_width="match_parent"
14             android:layout_height="0dp"
15             android:layout_weight="1"/>
16 
17         <TabWidget
18             android:id="@android:id/tabs"
19             android:layout_width="match_parent"
20             android:layout_height="?attr/actionBarSize"
21             android:layout_gravity="bottom"/>
22     </LinearLayout>
23 
24 </android.support.v4.app.FragmentTabHost>
复制代码

 说明:其中FrameLayout用于显示内容,TabWidget用于显示标签。

2.底部Tab布局:view_tab_indicator.xml

复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center">

    <ImageView
        android:id="@+id/tab_iv_image"
        android:layout_width="26dp"
        android:layout_height="26dp"
        android:contentDescription="@null"/>

    <TextView
        android:id="@+id/tab_tv_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="1dp"
        android:textColor="#ff847d7b"
        android:textSize="12sp"/>

</LinearLayout>
复制代码

底部Tab由一张图片和tab名称组成。

3.在mainActivity.java中定义一个内部类TabItem,用于表示底部tab:

复制代码
 1     class TabItem {
 2         //正常情况下显示的图片
 3         private int imageNormal;
 4         //选中情况下显示的图片
 5         private int imagePress;
 6         //tab的名字
 7         private int title;
 8         private String titleString;
 9         
10         //tab对应的fragment
11         public Class<? extends Fragment> fragmentClass;
12 
13         public View view;
14         public ImageView imageView;
15         public TextView textView;
16 
17         public TabItem(int imageNormal, int imagePress, int title,Class<? extends Fragment> fragmentClass) {
18             this.imageNormal = imageNormal;
19             this.imagePress = imagePress;
20             this.title = title;
21             this.fragmentClass =fragmentClass;
22         }
23 
24         public Class<? extends  Fragment> getFragmentClass() {
25             return fragmentClass;
26         }
27         public int getImageNormal() {
28             return imageNormal;
29         }
30 
31         public int getImagePress() {
32             return imagePress;
33         }
34 
35         public int getTitle() {
36             return  title;
37         }
38 
39         public String getTitleString() {
40             if (title == 0) {
41                 return "";
42             }
43             if(TextUtils.isEmpty(titleString)) {
44                 titleString = getString(title);
45             }
46             return titleString;
47         }
48 
49         public View getView() {
50             if(this.view == null) {
51                 this.view = getLayoutInflater().inflate(R.layout.view_tab_indicator, null);
52                 this.imageView = (ImageView) this.view.findViewById(R.id.tab_iv_image);
53                 this.textView = (TextView) this.view.findViewById(R.id.tab_tv_text);
54                 if(this.title == 0) {
55                     this.textView.setVisibility(View.GONE);
56                 } else {
57                     this.textView.setVisibility(View.VISIBLE);
58                     this.textView.setText(getTitleString());
59                 }
60                 this.imageView.setImageResource(imageNormal);
61             }
62             return this.view;
63         }
64 
65         //切换tab的方法
66         public void setChecked(boolean isChecked) {
67             if(imageView != null) {
68                 if(isChecked) {
69                     imageView.setImageResource(imagePress);
70                 }else {
71                     imageView.setImageResource(imageNormal);
72                 }
73             }
74             if(textView != null && title != 0) {
75                 if(isChecked) {
76                     textView.setTextColor(getResources().getColor(R.color.main_botton_text_select));
77                 } else {
78                     textView.setTextColor(getResources().getColor(R.color.main_bottom_text_normal));
79                 }
80             }
81         }
82     }
复制代码

4.初始化Tab数据:

复制代码
1     //初始化Tab数据
2     private void initTabData() {
3         mTableItemList = new ArrayList<>();
4         //添加tab
5         mTableItemList.add(new TabItem(R.drawable.main_bottom_home_normal,R.drawable.main_bottom_home_press,R.string.main_home_text, TestFragment1.class));
6         mTableItemList.add(new TabItem(R.drawable.main_bottom_attention_normal,R.drawable.main_bottom_attention_press,R.string.main_attention_text, TestFragment2.class));
7         mTableItemList.add(new TabItem(R.drawable.main_bottom_mine_normal,R.drawable.main_bottom_mine_press,R.string.main_mine_text, TestFragment3.class));
8 
9     }
复制代码

5.初始化选项卡视图:

复制代码
 1 //初始化主页选项卡视图
 2     private void initTabHost() {
 3         //实例化FragmentTabHost对象
 4         FragmentTabHost fragmentTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
 5         fragmentTabHost.setup(this,getSupportFragmentManager(),android.R.id.tabcontent);
 6 
 7         //去掉分割线
 8         fragmentTabHost.getTabWidget().setDividerDrawable(null);
 9 
10         for (int i = 0; i<mTableItemList.size(); i++) {
11             TabItem tabItem = mTableItemList.get(i);
12             //实例化一个TabSpec,设置tab的名称和视图
13             TabHost.TabSpec tabSpec = fragmentTabHost.newTabSpec(tabItem.getTitleString()).setIndicator(tabItem.getView());
14             fragmentTabHost.addTab(tabSpec,tabItem.getFragmentClass(),null);
15             
16             //给Tab按钮设置背景
17             fragmentTabHost.getTabWidget().getChildAt(i).setBackgroundColor(getResources().getColor(R.color.main_bottom_bg));
18 
19             //默认选中第一个tab
20             if(i == 0) {
21                 tabItem.setChecked(true);
22             }
23         }
24 
25         fragmentTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
26             @Override
27             public void onTabChanged(String tabId) {
28                 //重置Tab样式
29                 for (int i = 0; i< mTableItemList.size(); i++) {
30                     TabItem tabitem = mTableItemList.get(i);
31                     if (tabId.equals(tabitem.getTitleString())) {
32                         tabitem.setChecked(true);
33                     }else {
34                         tabitem.setChecked(false);
35                     }
36                 }
37             }
38         });
39     }
复制代码

6.在oncreate()中调用以上两个方法:

复制代码
1     @Override
2     protected void onCreate(Bundle savedInstanceState) {
3         super.onCreate(savedInstanceState);
4         setContentView(R.layout.activity_main);
5         initTabData();
6         initTabHost();
7     }
复制代码

至此,第一层tab实现完成,效果如下图所示:

 

第二层Tab实现:

第二层的tab基于第一层中的Fragment实现,本文使用了TabLayout和ViewPager。

注意:在使用TabLayout之前需要添加依赖包,例如在build.gradle中添加compile 'com.android.support:design:23.3.0'。

1.第二层tab的布局文件:

复制代码
 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:app="http://schemas.android.com/apk/res-auto"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:clickable="true"
 6     android:orientation="vertical">
 7 
 8 
 9     <android.support.design.widget.TabLayout
10         android:id="@+id/tab_essence"
11         android:layout_width="match_parent"
12         android:layout_height="40dp"
13         android:background="@color/essence_tab_bg"
14         app:tabMode="scrollable"
15         app:tabSelectedTextColor="@color/essence_tab_text_color_press"
16         app:tabTextColor="@color/essence_tab_text_color_normal"
17         app:tabIndicatorColor="@color/essence_tab_text_color_press"/>
18 
19     <android.support.v4.view.ViewPager
20         android:id="@+id/vp_essence"
21         android:layout_width="match_parent"
22         android:layout_height="match_parent"
23         app:layout_behavior="@string/appbar_scrolling_view_behavior" />
24 
25 </LinearLayout>
复制代码

其中TabLayout用于显示子tab,VierPager用于显示子tab对应的内容。

2.在strings.xml中配置标签数据:

复制代码
1     <array name="home_video_tab">
2         <item>全部@dream@0</item>
3         <item>视频@dream@1</item>
4         <item>声音@dream@2</item>
5         <item>图片@dream@3</item>
6         <item>段子@dream@4</item>
7         <item>广告@dream@5</item>
8         <item>剧情@dream@6</item>
9     </array>
复制代码

3.定义显示在ViewPager中的Fragment:

复制代码
 1 public class ContentFragment extends Fragment {
 2 
 3     private View viewContent;
 4     private int mType = 0;
 5     private String mTitle;
 6 
 7 
 8     public void setType(int mType) {
 9         this.mType = mType;
10     }
11 
12     public void setTitle(String mTitle) {
13         this.mTitle = mTitle;
14     }
15 
16 
17     @Nullable
18     @Override
19     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
20         //布局文件中只有一个居中的TextView
21         viewContent = inflater.inflate(R.layout.fragment_content,container,false);
22         TextView textView = (TextView) viewContent.findViewById(R.id.tv_content);
23         textView.setText(this.mTitle);
24 
25         return viewContent;
26     }
27 
28 }
复制代码

 

4.定义ViewPager的adapter:

复制代码
 1 //继承FragmentStatePagerAdapter
 2 public class TestFragmentAdapter extends FragmentStatePagerAdapter {
 3 
 4     public static final String TAB_TAG = "@dream@";
 5 
 6     private List<String> mTitles;
 7 
 8     public TestFragmentAdapter(FragmentManager fm, List<String> titles) {
 9         super(fm);
10         mTitles = titles;
11     }
12 
13     @Override
14     public android.support.v4.app.Fragment getItem(int position) {
15         //初始化Fragment数据
16         ContentFragment fragment = new ContentFragment();
17         String[] title = mTitles.get(position).split(TAB_TAG);
18         fragment.setType(Integer.parseInt(title[1]));
19         fragment.setTitle(title[0]);
20         return fragment;
21     }
22 
23     @Override
24     public int getCount() {
25         return mTitles.size();
26     }
27 
28     @Override
29     public CharSequence getPageTitle(int position) {
30         return mTitles.get(position).split(TAB_TAG)[0];
31     }
32 }
复制代码

5.Fragment具体实现:

复制代码
 1 public class TestFragment1 extends android.support.v4.app.Fragment{
 2 
 3     private View viewContent;
 4     private TabLayout tab_essence;
 5     private ViewPager vp_essence;
 6 
 7     @Nullable
 8     @Override
 9     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
10         viewContent = inflater.inflate(R.layout.fragment_test_1,container,false);
11         initConentView(viewContent);
12         initData();
13 
14         return viewContent;
15     }
16     
17     public void initConentView(View viewContent) {
18         this.tab_essence = (TabLayout) viewContent.findViewById(R.id.tab_essence);
19         this.vp_essence = (ViewPager) viewContent.findViewById(R.id.vp_essence);
20     }
21 
22     public void initData() {
23         //获取标签数据
24         String[] titles = getResources().getStringArray(R.array.home_video_tab);
25 
26         //创建一个viewpager的adapter
27         TestFragmentAdapter adapter = new TestFragmentAdapter(getFragmentManager(), Arrays.asList(titles));
28         this.vp_essence.setAdapter(adapter);
29 
30         //将TabLayout和ViewPager关联起来
31         this.tab_essence.setupWithViewPager(this.vp_essence);
32     }
33 }
复制代码

至此,第二层tab实现完成,效果如下:

总结:

1.本文实现的双层嵌套Tab使用到了FragmentTabHost,Fragment,ViewPager和TabLayout.

2.内外层的实现是解耦的,外层实现使用的是FragmentTabHost+Fragment,内层的实现是对外层Fragment的扩展,实现方式是使用TabLayout+VierPager。

 

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
实现 ViewPager2+TabLayout+Fragment 实现页面切换,需要以下步骤: 1. 在 XML 布局文件中定义 ViewPager2 和 TabLayout,并将它们嵌套在一个父布局中。 ```xml <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.tabs.TabLayout android:id="@+id/tab_layout" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabMode="scrollable" app:tabGravity="center"/> <androidx.viewpager2.widget.ViewPager2 android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintTop_toBottomOf="@id/tab_layout" app:layout_constraintBottom_toBottomOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout> ``` 2. 创建 Fragment,并实现 ViewPager2 的适配器。 ```kotlin class MyFragmentAdapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) { private val fragmentList = listOf( FirstFragment(), SecondFragment(), ThirdFragment() ) override fun getItemCount() = fragmentList.size override fun createFragment(position: Int) = fragmentList[position] } ``` 3. 在 Activity 或 Fragment 中,初始化 ViewPager2 和 TabLayout,并将适配器设置给 ViewPager2。 ```kotlin val viewPager: ViewPager2 = findViewById(R.id.view_pager) val tabLayout: TabLayout = findViewById(R.id.tab_layout) val adapter = MyFragmentAdapter(this) viewPager.adapter = adapter TabLayoutMediator(tabLayout, viewPager) { tab, position -> tab.text = "Tab ${position + 1}" }.attach() ``` 这样就可以实现 ViewPager2+TabLayout+Fragment 实现页面切换了。注意,TabLayoutMediator 是用来关联 TabLayout 和 ViewPager2 的,它的第一个参数是 TabLayout,第二个参数是 ViewPager2,第三个参数是一个回调函数,用来设置 TabLayout 的标签文本。在最后一行调用 attach() 方法即可完成关联。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值