Android TabLayout 使用进阶(含源码)(上)

简介: Android TabLayout 使用进阶(含源码)(上)

TabLayout 使用进阶


前言


对于Android开发来说,画页面算是必不可少的,因此你会接触很多不同的UI布局,你需要去绘制出来,在这过程中你已经接触过TabLayout。


演示效果图,这个图大概一分钟,请耐心看完。


20210430095943234.gif


扫描二维码下载APK试用


20210430100512326.png


正文


为了方便讲解,我依然是新建一个TabLayoutDemo项目来说明。


20210428091212427.png


一、控件基础使用


首先在现在的版本中,TabLayout已经迁移到androidx下了。因此先在你的app下的build.gradle中的dependencies{}闭包下添加如下依赖:


implementation 'com.google.android.material:material:1.2.1'


添加之后点击Sync Now同步一下。


同样为了方便演示我这里的MainActivity的布局中只放按钮,方便根据不同的使用方式进入不同的页面进行相应的演示。下面修改activity_main.xml。


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <Button
        android:text="基础使用"
        android:onClick="mode1"
        android:layout_width="match_parent"
        android:layout_height="50dp"/>
</LinearLayout>


在MainActivity中新增一个方法。


  /**
     * 基础使用
     * @param view
     */
    public void mode1(View view) {
    }


这个命名就不是很规范,实际中不要这么做,我这样是为了方便演示。


而基础的使用也需要进入一个新的Activity,那么很简单,在com.llw.tablayoutdemo下新建一个mode1,这个包下新建一个BasicUseActivity,布局是activity_basic_use.xml。


接下来从MainActivity通过点击按钮进入BasicUseActivity。


  public void mode1(View view) {
        startActivity(new Intent(this, BasicUseActivity.class));
    }


下面修改activity_basic_use.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".mode1.BasicUseActivity">
    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FFF" />
</LinearLayout>


这里面只有一个TabLayout。回到BasicUseActivity中,使用它。


① 设置标题


public class BasicUseActivity extends AppCompatActivity {
    private TabLayout tabLayout;
    /**
     * 标题数组
     */
    private String[] titles = {"one","two","three","four","five"};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_basic_use);
        tabLayout = findViewById(R.id.tab_layout);
        for (String title : titles) {
            //设置标签标题
            tabLayout.addTab(tabLayout.newTab().setText(title));
        }
    }
}


下面运行一下:


20210428094859922.gif


这样标题就设置好了,不过你会看到这个标题我设置的是英文小写,而这运行出来就变成了大写,这个原理有Button是一样的,你只需要将textAllCaps属性设置为false就可以了。


但是你发现这个TabLayout控件中并没有找到这个属性,这可怎么办呢?


设置样式,在你的res → values → styles.xml,在里面增加


  <!--Tab英文文字小写-->
    <style name="TabTextAllCapStyle" parent="TextAppearance.Design.Tab">
        <!--不启用大写-->
        <item name="textAllCaps">false</item>
    </style>


然后通过


app:tabTextAppearance="@style/TabTextAllCapStyle"


设置到这个控件里面就可以了,如下所示。


  <com.google.android.material.tabs.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FFF"
        app:tabTextAppearance="@style/TabTextAllCapStyle" />


再运行一下:


20210428095813458.png


可以看到变成了小写。


20210428100950956.png


我觉得还是有搞头的,试试看。


修改代码


    //标签选中监听
        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            /**
             * 选中
             * @param tab
             */
            @RequiresApi(api = Build.VERSION_CODES.M)
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                //大写
                tab.setText(titles[tab.getPosition()].toUpperCase());
            }
            /**
             * 未选中
             * @param tab
             */
            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
                //小写
                tab.setText(titles[tab.getPosition()].toLowerCase());
            }
            /**
             * 重新选中
             * @param tab
             */
            @Override
            public void onTabReselected(TabLayout.Tab tab) {
        //大写
                tab.setText(titles[tab.getPosition()].toUpperCase());
            }
        });

20210428102209603.png


下面运行一下:


202104281028469.gif


可以看到这样就可以使用实现了,只不过这是对于英文标题来说的,而中文标题的话通常我们是在选中时更改文字大小,而上图中,你会发现第一次进入时,是默认选中的第一个Tab,它的文字并没有大写,这是因为它没有触发监听,那么可以通过代码来设置。


    //选中第一个
        tabLayout.getTabAt(0).select();


这样设置就可以了。


② 设置图标


TabLayout也是可以设置图标的。首先放入五个图标

20210428104730913.png

20210428104730910.png

20210428104730900.png

20210428104730902.png

20210428104730910.png


然后添加图标数组


  /**
     * 标题图标
     */
    private Integer[] icons = {R.mipmap.common_problem, R.mipmap.community_me, R.mipmap.good_line,
            R.mipmap.live, R.mipmap.umbrella_line};


再修改一个刚才的for循环


  for (int i = 0;i < titles.length; i++){
            //设置标签标题和图标
            tabLayout.addTab(tabLayout.newTab().setText(titles[i]).setIcon(icons[i]));
        }


这里你必须保证标题和图标数量一致,否则就会出现数组越界的情况导致程序崩溃。

下面运行一下。


20210428105101895.gif


这样看起来是不是很像一些App主页面的底部操作栏了,这个后面我会讲到的,怎么使用TabLayout+ViewPager+Fragment打造App主页面。


③ 设置下划线


从上面的图可以看到TabLayout默认是一个下划线的,这个下划线默认的颜色比较的丑,我们修改一下它。


通过


  app:tabIndicatorColor="#00FF00"


就可以设置下划线的颜色了00FF00就是原谅绿。爱是一道光,绿到你发慌。


然后再通过


app:tabTextColor="#00FF00" 


把标签的文字颜色也改成这个原谅绿,

20210428110202780.png


运行看看。


20210428110557993.gif


啧啧啧,是不是很环保啊!这个颜色。然后你如果不需要下划线,最简单的办法就是设置透明,


app:tabIndicatorColor="#00000000"


这样设置就看不到下划线了。


当然更多实际需求是修改下划线的长度可以随文字大小改变而改变,这个设置其实也比较的简单,超出你想象之外的简单。


通过


app:tabIndicatorFullWidth="false"

20210428111146335.png


运行一下:


20210428111352108.gif


是不是很简单呢?基本上这个就能满足你的需求了,那么这个TabLayout的基本使用就介绍完了,有想要我添加的可以评论区留言哦,否则我就会以为你们都会了。


二、分类页面 (TabLayout + ViewPager + Fragment)


什么是分类页面呢?


20210428112030749.gif

20210428112515293.gif


可以看到类似与这种的都可以称之为分类页面,当然这是我的个人看法,我没有见过什么世面,浅显的这么认为。那么这样的页面看起来不错,但是怎么去入手呢?


分析一下可能就是TabLayout + ViewPager + Fragment构成的,这三个组合在写分类页面和App主页面时稍有不同,文中都会讲到的,莫急。


为了更好的演示,我还是会新建一个Activity,在com.llw.tablayoutdemo下新建一个mode2包,该包下新建ClassificationActivity,布局activity_classification.xml,布局代码:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".mode2.ClassificationActivity">
    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FFF"
        app:tabIndicatorColor="#00FF00"
        app:tabIndicatorFullWidth="false"
        app:tabMode="scrollable"
        app:tabRippleColor="#00000000"
        app:tabSelectedTextColor="#00FF00"
        app:tabTextColor="#000" />
    <androidx.viewpager.widget.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>


还差Fragment了,假设当前的Activity是要做视频的分类,有类别如下:电视剧、电影、综艺、体育、新闻、国际这六项。那么我们就需要建6个Fragment,这个些fragment同样放在mode2包下。分别是


① 创建Fragment


TVSeriesFragment


public class TVSeriesFragment extends Fragment {
    @Override
    public View onCreateView(final LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.fragment_tv_series,
                container, false);
        return view;
    }
}


MovieFragment


public class MovieFragment extends Fragment {
    @Override
    public View onCreateView(final LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.fragment_movie,
                container, false);
        return view;
    }
}


VarietyShowFragment


public class VarietyShowFragment extends Fragment {
    @Override
    public View onCreateView(final LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.fragment_variety_show,
                container, false);
        return view;
    }
}


SportsFragment


public class SportsFragment extends Fragment {
    @Override
    public View onCreateView(final LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.fragment_sports,
                container, false);
        return view;
    }
}


NewsFragment


public class NewsFragment extends Fragment {
    @Override
    public View onCreateView(final LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.fragment_news,
                container, false);
        return view;
    }
}


InternationalFragment。


public class InternationalFragment extends Fragment {
    @Override
    public View onCreateView(final LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.fragment_international,
                container, false);
        return view;
    }
}


六个Fragment各自对应的xml如下:


fragment_tv_series.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:gravity="center"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="电视剧"
        android:textColor="#000"
        android:textSize="24sp" />
</LinearLayout>


fragment_movie.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:gravity="center"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="电影"
        android:textColor="#000"
        android:textSize="24sp" />
</LinearLayout>


fragment_variety_show.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:gravity="center"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="综艺"
        android:textColor="#000"
        android:textSize="24sp" />
</LinearLayout>


fragment_sports.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:gravity="center"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="体育"
        android:textColor="#000"
        android:textSize="24sp" />
</LinearLayout>


fragment_news.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:gravity="center"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="新闻"
        android:textColor="#000"
        android:textSize="24sp" />
</LinearLayout>


fragment_international.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:gravity="center"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="国际"
        android:textColor="#000"
        android:textSize="24sp" />
</LinearLayout>


我这么实在的博主现在可不多了,这么多余的代码我都给贴出来了。


② Fragment适配器


现在Fragment的就写好了。下面写一个适配器,在com.llw.tablayoutdemo下新建一个adapter包,该包下新建一个BasicFragmentAdapter,里面的代码如下:


package com.llw.tablayoutdemo.adapter;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import java.util.List;
/**
 * Fragment适配器
 *
 * @author llw
 * @date 2021/4/28 15:08
 */
public class BasicFragmentAdapter extends FragmentPagerAdapter {
    String titleArr[];
    List<Fragment> mFragmentList;
    public BasicFragmentAdapter(FragmentManager fm, List<Fragment> list, String[] titleArr) {
        super(fm);
        mFragmentList = list;
        this.titleArr = titleArr;
    }
    @Override
    public Fragment getItem(int i) {
        return mFragmentList.get(i);
    }
    @Override
    public int getCount() {
        return mFragmentList != null ? mFragmentList.size() : 0;
    }
    @Nullable
    @Override
    public CharSequence getPageTitle(int position) {
        return titleArr[position];
    }
    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
//        super.destroyItem(container, position, object);
    }
}
相关文章
|
6月前
|
开发工具 Android开发 git
Windows下载android2.2完整源码(转)
Windows下载android2.2完整源码(转)
83 3
|
3月前
|
Ubuntu 开发工具 Android开发
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
本文介绍了在基于Ubuntu 22.04的环境下配置Python 3.9、安装repo工具、下载和同步AOSP源码包以及处理repo同步错误的详细步骤。
217 0
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
|
3月前
|
开发工具 git 索引
repo sync 更新源码 android-12.0.0_r34, fatal: 不能重置索引文件至版本 ‘v2.27^0‘。
本文描述了在更新AOSP 12源码时遇到的repo同步错误,并提供了通过手动git pull更新repo工具来解决这一问题的方法。
123 1
|
3月前
|
Android开发 Docker 容器
docker中编译android aosp源码,出现Build sandboxing disabled due to nsjail error
在使用Docker编译Android AOSP源码时,如果遇到"Build sandboxing disabled due to nsjail error"的错误,可以通过在docker run命令中添加`--privileged`参数来解决权限不足的问题。
587 1
|
3月前
|
开发工具 uml git
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
本文分享了下载AOSP源码的方法,包括如何使用repo工具和处理常见的repo sync错误,以及配置Python环境以确保顺利同步特定版本的AOSP代码。
413 0
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
|
3月前
|
Java Android开发 芯片
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
本文介绍了如何将基于全志H713芯片的AOSP Android源码导入Android Studio以解决编译和编码问题,通过操作步骤的详细说明,展示了在Android Studio中利用代码提示和补全功能快速定位并修复编译错误的方法。
123 0
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
|
3月前
|
Android开发
我的Android 进阶修炼(1): AOSP源码根目录结构
本文介绍了AOSP源码的根目录结构,提供了基于MTK9269 Android 9.0源码的目录说明,帮助读者了解AOSP源码的组织方式和各目录的功能。
163 0
我的Android 进阶修炼(1): AOSP源码根目录结构
|
3月前
|
API 开发工具 Android开发
Android源码下载
Android源码下载
448 0
|
3月前
|
开发工具 Android开发 git
全志H713 Android 11 :给AOSP源码,新增一个Product
本文介绍了在全志H713 Android 11平台上新增名为myboard的产品的步骤,包括创建新的device目录、编辑配置文件、新增内核配置、记录差异列表以及编译kernel和Android系统的详细过程。
104 0
|
3月前
|
Ubuntu 开发工具 Android开发
Repo下载、编译AOSP源码:基于Ubuntu 21.04,android-12.1.0_r27
文章记录了作者在Ubuntu 21.04服务器上配置环境、下载并编译基于Android 12.1.0_r27版本的AOSP源码的过程,包括解决编译过程中遇到的问题和错误处理方法。
179 0