zoukankan      html  css  js  c++  java
  • 使用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。

  • 相关阅读:
    2013-05-25 14:04 zend studio10正式版如何汉化?
    网页前端优化之滚动延时加载图片
    appium框架之bootstrap
    软件测试面试题(一)
    Java中的经典算法之冒泡排序(Bubble Sort)
    Git知识总览(一) 从 git clone 和 git status 谈起
    Webdriver获取多个元素
    idea注册码到期,破解idea
    安装appium桌面版和命令行版
    Python+Appium学习篇之WebView处理
  • 原文地址:https://www.cnblogs.com/happyhacking/p/5573246.html
Copyright © 2011-2022 走看看