美文网首页
TabHost+ViewPager实现底部导航效果

TabHost+ViewPager实现底部导航效果

作者: 块码加编 | 来源:发表于2020-08-13 13:24 被阅读0次

    一:摘要

    这篇文章主要为大家介绍了使用ViewPager+TabHost实现底部导航效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。

    下面我们先来看一下要实现的效果吧!

    二:具体实现过程

    1.新建一个project,把主布局改为TabHost,id为tab_host

    2.主布局添加一个相对布局,相对布局里加一个id为view_pager的 ViewPager布局。

    加一个id为@android:id/tabs的TabWidget(指明高度)并将其放在最底部。

    由于TabWidget要求必须要有一个id为@android:id/tabcontent的FrameLayout,所以得再加一个FrameLayout。

    为了看出界限,我们还要添加一条id为tab_divider线,具体可用View实现。

    从上往下,对组件进行排布。

    ViewPager和FrameLayout的layout_above="@+id/tab_divider",

    View的layout_above="@android:id/tabs",

    TabWidget的layout_alignParentBottom="true"。

    最后,让FrameLayout的visibility="gone"。

    3.创建一个TestFragment类继承Fragment并复写onCreate,onCreateView方法。

    4.创建fragment_test.xml文件。里面添加一个id为text_view的TextView。

    5.在TestFragment的onCreateView方法中,删除原有代码,通过布局反向生成view对象并加以返回。

    部分代码:

    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    
       //删除原有代码,通过布局反向生成view对象并加以返回。
       View view=inflater.inflate(R.layout.fragment_test,null);
       TextView textView=view.findViewById(R.id.text_view);
       return view;
    }
    

    6.因为要给TestFragment传参数(标题),所以得写一个静态方法来实现newInstance。

    部分代码:

    public static TestFragment newInstance(String title){
       TestFragment testFragment=new TestFragment();
       //建立一个bundle
       Bundle bundle=new Bundle();
       bundle.putString(TITLE,title);
       testFragment.setArguments(bundle);
       return testFragment;
    
    }
    //该方法里设置一个bundle用来testFragment.setArguments(bundle);可以把title提取为常量TITLE。
    
    

    7.在TestFragment的onCreate的方法里,我们要判断是否接受了数据,如果接受了数据,则把数据给提取出来。这时,我们可以把接受到的字符提取为一个叫mTitle的全局变量。

    部分代码:

    public void onCreate(@Nullable Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       if (getArguments()!=null){
           mTitle = getArguments().getString(TITLE);
       }
    }
    

    8.因为有了传参,所以在TestFragment的onCreateView的方法里,我们要把对应布局的TextView找到,设置TextView的文本为传入的参数mTitle。

    部分代码:

    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    
       //删除原有代码,通过布局反向生成view对象并加以返回。
       View view=inflater.inflate(R.layout.fragment_test,null);
       TextView textView=view.findViewById(R.id.text_view);
       textView.setText(mTitle);
       return view;
    }
    

    9.在MainActivity把ViewPager引用出来,记为mViewPager。

    10.我们要用三个fragment组成的viewpager。因此,先创建final Fragment [] fragments数组。注意分号

    部分代码:

    final Fragment[] fragments=new Fragment[]{
           TestFragment.newInstance("home"),
           TestFragment.newInstance("message"),
           TestFragment.newInstance("me")
    };//注意分号
    

    11.给mViewPager设置适配器。

    部分代码:

    mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {……};
    
    /*
    要重写两个方法,getItem和getCount。
    
    getItem中,return fragments[position];
    
    getCount中,return fragments.length
    */
    

    至此,上面部分已经完成。

    我们来看看效果。

    12.我们建立一个main_tab_layout.xml文件(相对布局),id为tab_bg。

    里面加一个id为main_tab_icon的ImageView,id为main_tab_text的TextView。设置好控件的外边距。

    如果以后有需要在右上角做一个小红点的话,可以把这两个放在一个id为main_contain的LinearLayout里,小红点在LinearLayout就行。

    13.main_tab_layout.xml里的文本,点击和没点击会显示不同的颜色,所以我们可以用textColor="@color/color_main_tab_text"来实现。

    新建color_main_tab_text布局,在其中的选择器selector里,添加item标签

    (注意顺序,显示特殊情况下的选择,最后才是默认情况下的选择,否则会失效)

        <item android:state_selected="true" android:color="#4dd048"/>
    
        <item android:state_pressed="true" android:color="#4dd048"/>
    
        <item android:color="#cccccc"/>
    

    14.同理,我们可以在drawable里也建立3个选择器。可以直接把color_main_tab_text布局文件复制到drawable后改名改参数即可。

    15.复制准备好的图片到drawable文件夹。对布局文件的参数进行修改。(注意顺序)

        <item android:state_selected="true" android:drawable="@drawable/tabbar_home_pressed"/>
    
        <item android:state_pressed="true" android:drawable="@drawable/tabbar_home_pressed"/>
    
        <item android:drawable="@drawable/tabbar_home"/>
    

    16.初始化总布局。把TabHost找出来并提取为全局变量mTabHost。调用mTabHost.setup();

    17.三个Tab做处理。三个Tab做处理,用数组来准备。

    int [] titlesIDs={R.string.home,R.string.message,R.string.me};//利用alt+enter为其设值。
    
            int [] drawableIDs={
    
                    R.drawable.color_main_tab_icon_home,
    
                    R.drawable.color_main_tab_icon_message,
    
                    R.drawable.color_main_tab_icon_me
    
            };
    

    18.利用for循环把数据填充到布局里。

    先把视图提取出来,给mIcon设置图片,给title设置文本,给tab设置背景颜色。

    调用mTabHost.addTab方法。因为该方法的setContent()要设置视图内容,我们可以通过让该类实现一个TabContentFactory接口来解决。

    部分代码:

    //数据填到视图里
    for (int index = 0; index < titlesIDs.length; index++) {
       //先把视图提取出来
       View view=getLayoutInflater().inflate(R.layout.main_tab_layout,null,false);
    
       ImageView mIcon=view.findViewById(R.id.main_tab_icon);
       TextView mTitle=view.findViewById(R.id.main_tab_text);
       View tab=view.findViewById(R.id.tab_bg);
    
       mIcon.setImageResource(drawableIDs[index]);
       mTitle.setText(titlesIDs[index]);
    
       //tab背景颜色,可以创建一个value
       tab.setBackgroundColor(getResources().getColor(R.color.myColor));
    
       mTabHost.addTab(
               mTabHost.newTabSpec(getString(titlesIDs[index]))
               .setIndicator(view)//设置分割
                //因为实现了TabContentFactory接口,所以我们就可以用this
                .setContent(this)    );
    }
    

    19.MainActivity实现TabContentFactory接口,重写方法createTabContent。

    在createTabContent中,直接创建一个view并返回就行。

    因为下面的要对应上上面的内容,而我们的内容是用ViewPager做的,虽然我们不要这个内容,但要求我们必须设置,所以直接返回一个view。我们可以把它隐藏掉。

    部分代码:

    public View createTabContent(String tag) {
       /*因为下面的要对应上上面的内容,而我们的内容是用ViewPager做的,
       虽然我们不要这个内容,但要求我们必须设置,所以直接返回一个view。我们可以把它隐藏掉。
        */
       View view=new View(this);
       view.setMinimumWidth(0);
       view.setMinimumHeight(0);
       return view;
    }
    

    至此,界面基本完成。

    20.我们看到底下有分割线,

    在activity_main的TabWidget里,可以通过调用

    android:showDividers="none"去掉分割线

    21.最后,添加互动。

    给mViewPager添加监听器。

    部分代码:

    mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {……}
    
    //在方法onPageSelected中先判断mTabHost是否为空,
    //不为空则调用mTabHost.setCurrentTab(position);方法。具体如下:
    
    public void onPageSelected(int position) {
       if(mTabHost!=null){
           mTabHost.setCurrentTab(position);
       }
    }
    

    22.给mTabHost添加监听器。

    部分代码:

    /*
    mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {……}
    
    onTabChanged方法中,先判断mTabHost && mViewPager是否为空。
    
    如果两个都不为空的话,则调用mViewPager.setCurrentItem(mTabHost.getCurrentTab());具体如下:
    */
    mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
       @Override
       public void onTabChanged(String tabId) {
           if(mViewPager!=null&&mTabHost!=null){
               //写法1
               //mViewPager.setCurrentItem(mTabHost.getCurrentTab());
               //写法2
               int position = mTabHost.getCurrentTab();
               mViewPager.setCurrentItem(position);
           }
       }
    });
    

    至此,全部功能已经完成。

    下面提供全部代码,欢迎小伙伴们交流学习。

    MainActivity:

    package com.wxdgut.navigation;
    
    import androidx.annotation.NonNull;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.fragment.app.Fragment;
    import androidx.fragment.app.FragmentPagerAdapter;
    import androidx.viewpager.widget.ViewPager;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.ImageView;
    import android.widget.TabHost;
    import android.widget.TextView;
    
    public class MainActivity extends AppCompatActivity implements TabHost.TabContentFactory {
    
       private TabHost mTabHost;
    
       @Override
       protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           setContentView(R.layout.activity_main);
    
           mTabHost = findViewById(R.id.tab_host);
           mTabHost.setup();
           //三个Tab做处理,用数组来准备
           int [] titlesIDs= new int[]{R.string.home, R.string.message, R.string.me};
           int [] drawableIDs={
                   R.drawable.main_tab_icon_home,
                   R.drawable.main_tab_icon_message,
                   R.drawable.main_tab_icon_me
           };
    
           //数据塞到视图里
           for (int index = 0; index < titlesIDs.length; index++) {
               //先把视图提取出来
    
                View view=
    
                getLayoutInflater().inflate(R.layout.main_tab_layout,null,false);
    
               ImageView mIcon=view.findViewById(R.id.main_tab_icon);
               TextView mTitle=view.findViewById(R.id.main_tab_text);
               View tab=view.findViewById(R.id.tab_bg);
    
               mIcon.setImageResource(drawableIDs[index]);
               mTitle.setText(titlesIDs[index]);
    
               //tab背景颜色,可以创建一个value
               tab.setBackgroundColor(getResources().getColor(R.color.myColor));
    
               mTabHost.addTab(
                       mTabHost.newTabSpec(getString(titlesIDs[index]))
                       .setIndicator(view)//设置分割
                       //因为实现了该接口,所以我们就可以用this
    
                        .setContent(this)
               );
    
           }
    
           final Fragment[] fragments=new Fragment[]{
                   TestFragment.newInstance("home"),
                   TestFragment.newInstance("message"),
                   TestFragment.newInstance("me")
           };//注意分号
    
           final ViewPager mViewPager= findViewById(R.id.view_pager);
           mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
               @NonNull
               @Override
               public Fragment getItem(int position) {
                   return fragments[position];
               }
    
               @Override
               public int getCount() {
                   return fragments.length;
               }
           });
    
           //做互动,将tab与viewpager关联
           mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
               @Override
               public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    
               }
    
               @Override
               public void onPageSelected(int position) {
                   if(mTabHost!=null){
                       mTabHost.setCurrentTab(position);
                   }
               }
    
               @Override
               public void onPageScrollStateChanged(int state) {
    
               }
           });
           mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
               @Override
               public void onTabChanged(String tabId) {
                   if(mViewPager!=null&&mTabHost!=null){
                       //写法1
                       //mViewPager.setCurrentItem(mTabHost.getCurrentTab());
                       //写法2
                       int position = mTabHost.getCurrentTab();
                       mViewPager.setCurrentItem(position);
                   }
               }
           });
       }
    
       @Override
       public View createTabContent(String tag) {
           /*因为下面的要对应上上面的内容,而我们的内容是用ViewPager做的,
           虽然我们不要这个内容,但要求我们必须设置,所以直接返回一个view。我们可以把它隐藏掉。
            */
           View view=new View(this);
           view.setMinimumWidth(0);
           view.setMinimumHeight(0);
           return view;
       }
    }
    

    TestFragment:

    package com.wxdgut.navigation;
    
    import android.os.Bundle;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.TextView;
    
    import androidx.annotation.NonNull;
    import androidx.annotation.Nullable;
    import androidx.fragment.app.Fragment;
    
    public class TestFragment extends Fragment {
    
       public static final String TITLE = "title";
       private String mTitle;
    
       public static TestFragment newInstance(String title){
           TestFragment testFragment=new TestFragment();
           //建立一个bundle
           Bundle bundle=new Bundle();
           bundle.putString(TITLE,title);
           testFragment.setArguments(bundle);
           return testFragment;
    
       }
       @Override
       public void onCreate(@Nullable Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           if (getArguments()!=null){
               mTitle = getArguments().getString(TITLE);
           }
       }
    
       @Nullable
       @Override
       public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
           //删除原有代码,通过布局反向生成view对象并加以返回。非activity中就用inflater
           View view=inflater.inflate(R.layout.fragment_test,null);
           TextView textView=view.findViewById(R.id.text_view);
           textView.setText(mTitle);
           return view;
       }
    }
    

    activity_main.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <TabHost xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:app="http://schemas.android.com/apk/res-auto"
       xmlns:tools="http://schemas.android.com/tools"
       android:id="@+id/tab_host"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       tools:context=".MainActivity"
       android:orientation="vertical">
    
       <RelativeLayout
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:orientation="vertical">
           <androidx.viewpager.widget.ViewPager
               android:id="@+id/view_pager"
               android:layout_width="match_parent"
               android:layout_height="match_parent"
               android:layout_above="@+id/tab_divider">
    
           </androidx.viewpager.widget.ViewPager>
    
           <FrameLayout
               android:id="@android:id/tabcontent"
               android:layout_width="match_parent"
               android:layout_height="match_parent"
               android:layout_above="@+id/tab_divider"
               android:visibility="gone"/>
    
           <View
               android:id="@+id/tab_divider"
               android:layout_width="match_parent"
               android:layout_height="5dp"
               android:background="#dfdfdf"
               android:layout_above="@android:id/tabs"/>
    
           <TabWidget
               android:id="@android:id/tabs"
               android:layout_width="match_parent"
               android:layout_height="80dp"
               android:showDividers="none"
               android:layout_alignParentBottom="true"/>
    
       </RelativeLayout>
    
    </TabHost>
    

    fragment_test.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:orientation="vertical"
       android:gravity="center">
    
       <TextView
           android:id="@+id/text_view"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="wxdgut.com"
           android:textSize="25sp" />
    
    </LinearLayout>
    

    main_tab_layout.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:id="@+id/tab_bg">
    
       <LinearLayout
           android:id="@+id/main_content"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:orientation="vertical"
           android:gravity="center"
           android:layout_centerInParent="true">
           <ImageView
               android:id="@+id/main_tab_icon"
               android:layout_width="30dp"
               android:layout_height="30dp"
               android:src="@mipmap/ic_launcher"
               android:layout_marginTop="4dp"/>
           <TextView
               android:id="@+id/main_tab_text"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@string/app_name"
               android:textColor="@color/color_main_tab_text"
               android:layout_marginTop="5dp"/>
       </LinearLayout>
       //以后可以做个小红点
       <ImageView
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:visibility="gone"/>
    
    </RelativeLayout>
    

    color_main_tab_text.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
       //注意顺序,显示特殊情况下的选择,最后才是默认情况下的选择,否则会失效
       <item android:state_selected="true" android:color="#4dd048"/>
       <item android:state_pressed="true" android:color="#4dd048"/>
       <item android:color="#cccccc"/>
    </selector>
    

    main_tab_icon_home.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
       //注意顺序,显示特殊情况下的选择,最后才是默认情况下的选择,否则会失效
       <item android:drawable="@drawable/tabbar_home_pressed" android:state_selected="true" />
       <item android:drawable="@drawable/tabbar_home_pressed" android:state_pressed="true" />
       <item android:drawable="@drawable/tabbar_home" />
    </selector>
    

    main_tab_icon_me.xml和main_tab_icon_message.xml:同上面的类似。

    接下来是图片素材,需要的话就保存一下吧。

    1

    tabbar_home_pressed

    2

    tabbar_home

    3

    tabbar_msg_pressed

    4

    tabbar_msg

    5

    tabbar_my_pressed

    6

    tabbar_my

    欢迎小伙伴们批评指正!

    相关文章

      网友评论

          本文标题:TabHost+ViewPager实现底部导航效果

          本文链接:https://www.haomeiwen.com/subject/crpbdktx.html