TabLayout+ViewPager 简单实现app底部Tab

作者: Fi7z | 来源:发表于2015-12-01 10:13 被阅读36488次

    前言

    在谷歌发布Android Design Support Library之前,app底部tab布局的实现方法就有很多种,其中有RadioGroup+FrameLayout、TabHost+Fragment、FragmentPagerAdapter+ViewPager等方法,虽然这些方法虽然能达到同样的效果,但我个人总觉得有些繁琐。然而,Google在2015的IO大会上,给开发者们带来了全新的Android Design Support Library,里面包含了许多新控件,这些新控件有许多是把以前的一些第三方开源库官方化,实现起来更为简便,简直是开发者的福音。其中的TabLayout控件让我想到了app底部的tab布局,而且TabLayout用法更加简单,为何不试试用TabLayout实现简单的实现呢?好了,话不多说,先看看效果:

    底部tab布局.png

    是不是和以前的方法实现的效果一样呢?下面我们来看看怎么简单实现。

    过程

    因为TabLayout和ViewPager分别是属于design和v4包下的,所以我们先在app的build.gradle中添加:

    compile 'com.android.support:design:23.1.1'
    compile 'com.android.support:support-v4:23.1.1'
    

    然后在主布局文件activity_main.xml中添加布局控件:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">
    
        <android.support.v4.view.ViewPager
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:scrollbars="none">
        </android.support.v4.view.ViewPager>
    
        <android.support.design.widget.TabLayout
            android:id="@+id/tabLayout"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            app:tabGravity="fill"
            app:tabIndicatorHeight="0dp"
            app:tabMode="fixed"
            app:tabSelectedTextColor="#FF4081"
            app:tabTextColor="#000">
        </android.support.design.widget.TabLayout>
    
    </LinearLayout>
    

    就仅一个ViewPager和TabLayout就可以实现,是不是比以前的方法繁琐的布局简便很多?上面TabLayout中app:tabIndicatorHeight="0dp"是为了不显示tab底部的横线,app:tabMode="fixed"是让底部tab布局不可滑动。

    接下来就和往常一样在MainActivity.java中初始化布局,设置适配器:

        private void initViews() {
    
            mTablayout= (TabLayout) findViewById(R.id.tabLayout);
            mViewPager= (ViewPager) findViewById(R.id.viewPager);
    
            mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
    
                private String[] mTitles = new String[]{"唐僧", "大师兄", "二师兄","沙师弟"};
    
                @Override
                public Fragment getItem(int position) {
                    if (position == 1) {
                        return new TwoFragment();
                    } else if (position == 2) {
                        return new ThreeFragment();
                    }else if (position==3){
                        return new FourFragment();
                    }
                    return new OneFragment();
                }
    
                @Override
                public int getCount() {
                    return mTitles.length;
                }
    
                @Override
                public CharSequence getPageTitle(int position) {
                    return mTitles[position];
                }
    
            });
    
            mTablayout.setupWithViewPager(mViewPager);
    
            one = mTablayout.getTabAt(0);
            two = mTablayout.getTabAt(1);
            three = mTablayout.getTabAt(2);
            four = mTablayout.getTabAt(3);
    
            one.setIcon(getResources().getDrawable(R.drawable.ic_favorite_black_18dp));
            two.setIcon(getResources().getDrawable(R.mipmap.ic_launcher));
            three.setIcon(getResources().getDrawable(R.mipmap.ic_launcher));
            four.setIcon(getResources().getDrawable(R.mipmap.ic_launcher));
    
        }
    

    上面要注意的地方是别忘了在FragmentPagerAdapter中手动添加:

                @Override
                public CharSequence getPageTitle(int position) {
                    return mTitles[position];
                }
    

    不然不显示底部的文字。
    mTablayout.setupWithViewPager(mViewPager);将TabLayout和ViewPager关联起来。
    one = mTablayout.getTabAt(0);获取底部单个tab,用来添加初始化图片,注意下标都是从0开始的。

    初始化监听事件

        private void initEvents() {
    
            mTablayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
                @Override
                public void onTabSelected(TabLayout.Tab tab) {
                    if (tab == mTablayout.getTabAt(0)) {
                        one.setIcon(getResources().getDrawable(R.drawable.ic_favorite_black_18dp));
                        mViewPager.setCurrentItem(0);
                    } else if (tab == mTablayout.getTabAt(1)) {
                        two.setIcon(getResources().getDrawable(R.drawable.ic_favorite_black_18dp));
                        mViewPager.setCurrentItem(1);
                    } else if (tab == mTablayout.getTabAt(2)) {
                        three.setIcon(getResources().getDrawable(R.drawable.ic_favorite_black_18dp));
                        mViewPager.setCurrentItem(2);
                    }else if (tab == mTablayout.getTabAt(3)){
                        four.setIcon(getResources().getDrawable(R.drawable.ic_favorite_black_18dp));
                        mViewPager.setCurrentItem(3);
                    }
    
                }
    
                @Override
                public void onTabUnselected(TabLayout.Tab tab) {
                    if (tab == mTablayout.getTabAt(0)) {
                        one.setIcon(getResources().getDrawable(R.mipmap.ic_launcher));
                    } else if (tab == mTablayout.getTabAt(1)) {
                        two.setIcon(getResources().getDrawable(R.mipmap.ic_launcher));
                    } else if (tab == mTablayout.getTabAt(2)) {
                        three.setIcon(getResources().getDrawable(R.mipmap.ic_launcher));
                    }else if (tab == mTablayout.getTabAt(3)){
                        four.setIcon(getResources().getDrawable(R.mipmap.ic_launcher));
                    }
                }
    
                @Override
                public void onTabReselected(TabLayout.Tab tab) {
    
                }
            });
    
        }
    

    在onTabSelected中设置选中tab时切换的图片,onTabUnselected中设置没有被选中时的图片。别忘了mViewPager.setCurrentItem(0);这句,这是用来点击tab时切换ViewPager,如果不加这一句的话滑动ViewPager底部tab可以切换,但是点击tab而ViewPager不会切换。

    Fragment中的简单布局

    fragment_one.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">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="唐僧"
            android:layout_marginTop="100dp"
            android:layout_gravity="center"
            android:textSize="30sp"/>
    
    </LinearLayout>
    
    OneFragment.java
    public class OneFragment extends Fragment{
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            return inflater.inflate(R.layout.fragment_one,container,false);
        }
    
        @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
        }
    }
    

    MainActivity.java完整代码:

    public class MainActivity extends AppCompatActivity {
    
        private TabLayout mTablayout;
        private ViewPager mViewPager;
    
        private TabLayout.Tab one;
        private TabLayout.Tab two;
        private TabLayout.Tab three;
        private TabLayout.Tab four;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initViews();
            initEvents();
        }
    
        private void initEvents() {
    
            mTablayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
                @Override
                public void onTabSelected(TabLayout.Tab tab) {
                    if (tab == mTablayout.getTabAt(0)) {
                        one.setIcon(getResources().getDrawable(R.drawable.ic_favorite_black_18dp));
                        mViewPager.setCurrentItem(0);
                    } else if (tab == mTablayout.getTabAt(1)) {
                        two.setIcon(getResources().getDrawable(R.drawable.ic_favorite_black_18dp));
                        mViewPager.setCurrentItem(1);
                    } else if (tab == mTablayout.getTabAt(2)) {
                        three.setIcon(getResources().getDrawable(R.drawable.ic_favorite_black_18dp));
                        mViewPager.setCurrentItem(2);
                    }else if (tab == mTablayout.getTabAt(3)){
                        four.setIcon(getResources().getDrawable(R.drawable.ic_favorite_black_18dp));
                        mViewPager.setCurrentItem(3);
                    }
    
                }
    
                @Override
                public void onTabUnselected(TabLayout.Tab tab) {
                    if (tab == mTablayout.getTabAt(0)) {
                        one.setIcon(getResources().getDrawable(R.mipmap.ic_launcher));
                    } else if (tab == mTablayout.getTabAt(1)) {
                        two.setIcon(getResources().getDrawable(R.mipmap.ic_launcher));
                    } else if (tab == mTablayout.getTabAt(2)) {
                        three.setIcon(getResources().getDrawable(R.mipmap.ic_launcher));
                    }else if (tab == mTablayout.getTabAt(3)){
                        four.setIcon(getResources().getDrawable(R.mipmap.ic_launcher));
                    }
                }
    
                @Override
                public void onTabReselected(TabLayout.Tab tab) {
    
                }
            });
    
        }
    
        private void initViews() {
    
            mTablayout= (TabLayout) findViewById(R.id.tabLayout);
            mViewPager= (ViewPager) findViewById(R.id.viewPager);
    
            mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
    
                private String[] mTitles = new String[]{"唐僧", "大师兄", "二师兄","沙师弟"};
    
                @Override
                public Fragment getItem(int position) {
                    if (position == 1) {
                        return new TwoFragment();
                    } else if (position == 2) {
                        return new ThreeFragment();
                    }else if (position==3){
                        return new FourFragment();
                    }
                    return new OneFragment();
                }
    
                @Override
                public int getCount() {
                    return mTitles.length;
                }
    
                @Override
                public CharSequence getPageTitle(int position) {
                    return mTitles[position];
                }
    
            });
    
            mTablayout.setupWithViewPager(mViewPager);
    
            one = mTablayout.getTabAt(0);
            two = mTablayout.getTabAt(1);
            three = mTablayout.getTabAt(2);
            four = mTablayout.getTabAt(3);
    
            one.setIcon(getResources().getDrawable(R.drawable.ic_favorite_black_18dp));
            two.setIcon(getResources().getDrawable(R.mipmap.ic_launcher));
            three.setIcon(getResources().getDrawable(R.mipmap.ic_launcher));
            four.setIcon(getResources().getDrawable(R.mipmap.ic_launcher));
    
        }
    }
    

    结束语

    以上就是简单用TabLayout+ViewPager实现app底部Tab布局的整个过程,如果你有更好的方法,或者文章中存在错误或不足的地方,欢迎在文章下面评论交流!

    相关文章

      网友评论

      • 那一年我愛過那女孩:java.lang.NoClassDefFoundError: android.support.v7.widget.TintManager 我使用您代码后 出现了这个问题
      • 987f86631625:你好 ,我写的为什么TabLayout一直在ViewPager的上方?能把他调到ViewPager下面么
        Fi7z:@乐乐0108 修改布局就行了
      • 松小白:顶部图片和底部文字中间很大空隙,该如何解决对其的问题?
        Fi7z:@松小白 通过setView方法自定义
      • 一梦付浮生:标题栏是在上面
      • 一梦付浮生:楼主为啥我的是反的
      • MrLi_d234:tab字体颜色变化出错问题可以通过 mTabLayout.setTabMode(TabLayout.MODE_FIXED);
        这行代码搞定!
        4b7b70976204:在哪里加?我加了木用
      • 左侧怀念:楼主,我设置了三个tab,但是当我选择第二个tab时,第一个tab的图片变了,但字体颜色没变(白色);选择第三个tab的时候,第一个tab的字体颜色恢复成灰色,第二个tab图片变了,但字体颜色没变(白色),这个是什么情况啊,哪里设置错了吗
        晨心w:同样,找到解决方案了呢?大神
      • 凝雲氷镧:compile 'com.android.support:design:23.1.1'
        compile 'com.android.support:support-v4:23.1.1'这个在build.gradle中添加了,为啥还是不能用啊 app:tabGravity 是红色的,出错
      • d08b1e4b2933:点击下面的tab 时,tab里的字体颜色变化出错,而滑动页面显示又是正确的,这是什么原因?
        AgonyTang:@晨心w 当然简单粗暴的干掉mTablayout.setOnTabSelectedListener 也不是最好的解决办法
        AgonyTang:@晨心w 这个Bug的根本原因还需要时间深入分析,但是解决办法是有的。mTablayout.setupWithViewPager(mViewPager);
        这行代码就是设置联动的,所以干掉
        mTablayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() ....
        这一行可以解决问题,就是会所不单独给mTablayout设置选中的回调监听。由此问题得到解决,同时也可以Bug点就在这里,为什么会出现这样的Bug,需要深入分析
        晨心w:有没有找到问题所在呢??
      • 0bf8c52810e6:亲,这个东西收藏好久了,今天第一次试,为啥我写出来底部图片在文字的左边而不是上方,还有啥我没加????
      • 7c20bdeaae48:目前是自己写的布局,先收藏。有空再看看
      • MnyZhao:博主 版本设置23 就可以 我用的24 不知道是因为啥 目前没找到原因
      • MnyZhao:图标是会改变 但是文字选中的颜色 是点击最近的两项
        ZenCabin: 出现这个问题的原因:
        你在给刚取消选中状态的tab设置为原来的icon时,即MainActivity里的mTabLayout的回调方法onTabUnselected里setIcon时,这个setIcon方法会在下面这段代码处,重新把tab的select状态给设置为了selected了,所以导致颜色又变成了红色,
        // setSelected(tab != null && tab.isSelected());
        左侧怀念:找到问题的根源没
        左侧怀念:我的也是这样
      • MnyZhao:这种方式 当你监听了tablelayout的事件之后滑动没问题 但是下面每一项 都会保留与之最近的一项的选中状态 就是选中了两项 不知道你单击试过没有
      • 狂猿:我测试了一下,不见TabLayout那几个事件监听也是可以的,点击tab的时候,viewPager也是可以滑动的
      • sendtion:不错,赞一个!有许多新特性需要挖掘!
      • null_null_:写的不太清楚
      • 李二十九:这样布局底部导航字体的大小怎么设置,如果我有五个导航键,title为四个字,会导致最后一个字显示不出来
        李白不喝酒:好的,多谢。我试试
        Fi7z: @李二十九 你可以用自定义的布局来填充tab,有setView()这个方法的
      • 绿色小晶体:6666666666收藏学习了
      • 24336da1e97a:如果屏幕的分辨率不同了 怎么来做适配呢
        Fi7z:@24336da1e97a 要适配的应该是图片啊,还是你说的是距离呢?
      • 苇渡:fragment中的内容虽然设置了layout_gravity=true,实际并不居中,而是偏上一些 请问这个怎么解决呢?
        Fi7z:@苇渡 那个,fragment是随便弄的一个布局。你看我加了一句android:layout_marginTop="100dp",就到中间了
      • 2e1547f17500:学习了
        😄
      • acc8aee6f63f:底部布局最优的方式是什么啊?找了很久没有个大神说一下这几种布局的特点
        Fi7z: @Jzl_ 没有最优的方式,都有优缺点。看你喜欢什么样的设计,其实我觉得底部tab布局的话用LinearLayout+ViewPager比较好一点
      • d0cface65557:getSupportFragmentManager()是什么啊?
        Fi7z:@永遠aiq天藍 获取FragmentManager(),Support是适配安卓低版本的
      • d0cface65557:可以共享下代码吗?
      • d0cface65557:您好,有完整的代码吗?
      • Chenstyle:最开始在 Gradle 中声明那个。应该是会自动声明的吧。。
        或者说声明规则是什么?
        Fi7z:@沉睡的大大_ 如果你刚开始创建工程的时候是一个空白的工程就不会自动声明。非空白的工程一般会自动声明。
      • __Berial___:可以通过写selector-xx.xml直接设置tab图标,避免总是setDrawable
        Fi7z: @__Berial___ 那样也可以,不过得加载自定义布局。也得写四个单独的tab布局才能用selector,因为考虑到有四个图片都是不一样的情况呢。
      • 曾樑:几种布局必须搞清楚的:+1:
        Fi7z:@曾樑 这些东西还是更新挺快的。所以,活到老学到老啊! :smile:

      本文标题:TabLayout+ViewPager 简单实现app底部Tab

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