icode icode
首页
  • Android学习

    • 📁基础内容
    • 📺AndroidCore
    • 🎨Android-UI
    • 🏖️Components
    • 📊Fragment
    • 🔗网络操作
    • 🔏异步机制
    • 📦数据存储
    • 🗃️Gradle
  • 学习笔记

    • 『框架』笔记
    • 『Kotlin』笔记
    • 《Vue》笔记
    • 《Git》学习笔记
    • 『Bug踩坑记录』
  • ListView
  • RecyclerView
  • ViewPager
  • Java笔记

    • 🟠JavaSE
    • 🟢JavaWeb
    • 🔴JavaEE
    • ⚪JavaTopic
    • 🍳设计模式
  • 计算机基础

    • 📌计算机网络
    • 🔍数据结构
    • 📦数据库
    • 💻OS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 关于

    • 📫关于我
  • 收藏

    • 网站
    • 资源
    • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

iqqcode

保持对技术的探索实践与热爱
首页
  • Android学习

    • 📁基础内容
    • 📺AndroidCore
    • 🎨Android-UI
    • 🏖️Components
    • 📊Fragment
    • 🔗网络操作
    • 🔏异步机制
    • 📦数据存储
    • 🗃️Gradle
  • 学习笔记

    • 『框架』笔记
    • 『Kotlin』笔记
    • 《Vue》笔记
    • 《Git》学习笔记
    • 『Bug踩坑记录』
  • ListView
  • RecyclerView
  • ViewPager
  • Java笔记

    • 🟠JavaSE
    • 🟢JavaWeb
    • 🔴JavaEE
    • ⚪JavaTopic
    • 🍳设计模式
  • 计算机基础

    • 📌计算机网络
    • 🔍数据结构
    • 📦数据库
    • 💻OS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 关于

    • 📫关于我
  • 收藏

    • 网站
    • 资源
    • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 基础内容

  • AndroidCore

  • Android UI

  • Components

    • ListView

    • RecyclerView

    • ViewPager

    • TabLayout

      • TabLayout使用详解
      • Android仿微信底部菜单栏+今日头条顶部导航栏
        • 前言
        • 底部菜单
          • 基本布局
          • 页面切换Adapter
          • 子页面实例
          • MainActivity
        • 顶部导航条
          • 自适应非固定条数
          • 消息内容子页面适配器
          • 消息内容页
        • Tablayut居中设置
          • 居中固定条数
          • 平铺固定条数
        • 总结
      • Tablayout属性使用全解
  • Fragment

  • 网络操作

  • 异步机制

  • 数据存储

  • 学习笔记

  • 自定义View

  • View事件体系

  • Android
  • Components
  • TabLayout
iqqcode
2021-08-25
目录

Android仿微信底部菜单栏+今日头条顶部导航栏

# 前言

现在很多APP功能点比较多,涉及的页面比较多,而底部又无法添加很多个Tab,底部导航栏基本都是4-5的样子。无法容纳更多页面,此时顶部导航栏采用TabLayout + ViewPager的方式来切换Fragment。

本节我们实现两种主要的Tab效果:

  1. 仿微信底部菜单
  2. 仿今日头条顶部导航条

Demo详见:https://github.com/IQQcode/WaddleConvince/tree/main/LayoutDesign/01TabLayoutNavigationGuide

效果预览:

guide-layout


# 底部菜单

Tab一般与Activity或Fragment配合使用,以达到多页面切换效果,这里使用Fragment来开发子界面。

微信形式的底部菜单可以理解为一个外层Activity,套用几个Fragment。页面布局层次为:

MainActivity 主框架

  • HomePageFragment 微信
  • maillistFragment 通讯录
  • FindFragment 发现
  • MeFragment 我

做出来的效果:

image-20210822103635897

# 基本布局

activity_main布局

ViewPager + TabLayout上下结构:

image-20210822151205875

<?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">

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:background="@color/line_gray" />

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="54dp"
        app:tabIndicatorHeight="0dp"/>

</LinearLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

Tab自定义视图item_main_menu.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_horizontal"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/img_tab"
        android:layout_width="24dip"
        android:layout_height="24dip"
        android:src="@drawable/menu_msg_default" />

    <TextView
        android:id="@+id/txt_tab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="2dip"
        android:text="首页"
        android:textColor="@drawable/txt_main_menu_selector"
        android:textSize="11sp" />

</LinearLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

Tab图标selector

以第一个Tab“微信”使用的图标为例,tab_main_msg_selector.xml内容

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/menu_msg_selected" android:state_pressed="true" />
    <item android:drawable="@drawable/menu_msg_selected" android:state_selected="true" />
    <item android:drawable="@drawable/menu_msg_default" />
</selector>
1
2
3
4
5
6

使用到了两张图片:menu_msg_default、menu_msg_selected,一张默认图样式,一张选中图样式,对比如下:

image-20210822104527526

Tab文字selector

因为Tab选中时需要做区分,所以文字颜色与图标一起变动会更好看,文字颜色也需要写selector。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/menu_green" android:state_selected="true"></item>
    <item android:color="@color/menu_gray"></item>
</selector>

1
2
3
4
5
6

menu_gray是默认状态的灰色,menu_green是选中时呈现的绿色。

# 页面切换Adapter

页面切换内容由ViewPager的adapter对象完成,使用Fragment作为子页面时,Adapter需要是FragmentPagerAdapter的实例,由于底部是四个Tab,所以要添加四个Fragment:

主界面底部菜单适配器 ViewPager的Adapter

public class MainFragmentAdapter extends FragmentPagerAdapter {

    private List<BaseFragment> fragmentList;

    public MainFragmentAdapter(@NonNull FragmentManager fm) {
        super(fm);
        addFragmentContainer();
    }

    private void addFragmentContainer() {
        fragmentList = new ArrayList<>();
        fragmentList.add(new HomePageFragment());
        fragmentList.add(new MailListFragment());
        fragmentList.add(new FindFragment());
        fragmentList.add(new MeFragment());
    }

    @NonNull
    @Override
    public Fragment getItem(int position) {
        return fragmentList.get(position);
    }

    @Override
    public int getCount() {
        return fragmentList.size();
    }

//    @Nullable
//    @Override
//    public CharSequence getPageTitle(int position) {
//        // 不用在主Activity添加tab标题,这里直接设置
//        return fragmentList.get(position).getTitle();
//    }

    /**
     * 防止viewpager在滑动切换的时候,里面的fragment被销毁,导致数据需要重新加载
     * @param container
     * @param position
     * @param object
     */
    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        super.destroyItem(container, position, object);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

【说明】:

  • getItem返回具体位置的viewPager切换到i位置时对应的fragment,因为主框架的视图是固定的,所以在这里根据i的值返回对应的fragment对象即可;
  • getItem中返回的fragment也可以携带一些参数,如果需要的话;
  • getCount返回视图的总数量,这里是取ArrayList的size(ArrayList存放Tab页面的Fragment)。

# 子页面实例

本例中的子页面只是呈现一个简单的文字,实际开发中根据需要写入相应布局和功能替换即可。这里以MeFragment作为示例:

MeFragment.java

public class MeFragment extends BaseFragment {

    private ImageView mImageView;
    private TextView mTextView;
    public MeFragment() { }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_continer_layout, container, false);
        mImageView = view.findViewById(R.id.binner_image);
        mTextView = view.findViewById(R.id.binner_title);
        mTextView.setText("我的内容");
        mImageView.setImageResource(R.drawable.tab_me);
        return view;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

fragment_continer_layout.xml

image-20210822113203742

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/binner_image"
        android:layout_width="300dp"
        android:layout_height="400dp"
        android:layout_centerHorizontal="true"
        android:src="@drawable/tab_chat"
        android:layout_marginTop="50dp" />

    <TextView
        android:id="@+id/binner_title"
        android:layout_below="@id/binner_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30dp"
        android:text="test"
        android:textStyle="bold"
        android:layout_marginTop="20dp"
        android:layout_centerHorizontal="true"/>

</RelativeLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# MainActivity

package top.iqqcode.guide;

import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;

import android.os.Bundle;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayout;

import top.iqqcode.guide.adapter.MainFragmentAdapter;

public class MainActivity extends AppCompatActivity {

    // 底部导航Tab资源文件
    private final int[] TAB_TILES = new int[] {R.string.menu_msg, R.string.menu_content, R.string.menu_find, R.string.menu_me};
    private final int[] TAB_IMAGES = new int[] {R.drawable.tab_main_msg_selector, R.drawable.tab_main_contact_selector, R.drawable.tab_main_find_selector, R.drawable.tab_main_me_selector};

    private ViewPager mViewPager;
    private TabLayout mTabLayout;

    private PagerAdapter mAdapter; // ViewPager Adapter
    private long exitTime;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
        initPager();
        setTabs(mTabLayout, getLayoutInflater(), TAB_TILES, TAB_IMAGES);
    }

    private void initView() {
        mViewPager = findViewById(R.id.view_pager);
        mTabLayout = findViewById(R.id.tab_layout);
    }

    // 初始化选项卡
    private void initPager() {
        mAdapter = new MainFragmentAdapter(getSupportFragmentManager());
        mViewPager.setAdapter(mAdapter);
        // 关联切换
        mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout));
        mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                // 取消平滑切换
                mViewPager.setCurrentItem(tab.getPosition(), false);
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });
    }

    /**
     * 设置底部页卡显示效果
     * @param mTabLayout
     * @param layoutInflater
     * @param tabTitles
     * @param tabImages
     */
    private void setTabs(TabLayout mTabLayout, LayoutInflater layoutInflater, int[] tabTitles, int[] tabImages) {
        for (int i = 0; i < tabImages.length; i++) {
            // 新建new tab
            TabLayout.Tab tab = mTabLayout.newTab();
            View view = layoutInflater.inflate(R.layout.item_main_menu, null);
            // 使用自定义视图,目的是为了便于修改,也可使用自带的视图
            tab.setCustomView(view);
            
            TextView tvTitle = (TextView) view.findViewById(R.id.txt_tab);
            tvTitle.setText(tabTitles[i]);
            ImageView imgTab = (ImageView) view.findViewById(R.id.img_tab);
            imgTab.setImageResource(tabImages[i]);
            mTabLayout.addTab(tab);
        }
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
                && event.getAction() == KeyEvent.ACTION_DOWN
                && event.getRepeatCount() == 0) {
            // 重写键盘事件分发,onKeyDown方法某些情况下捕获不到,只能在这里写
            if ((System.currentTimeMillis() - exitTime) > 2000) {
                Snackbar snackbar = Snackbar.make(mViewPager, "再按一次退出程序", Snackbar.LENGTH_SHORT);
                snackbar.getView().setBackgroundResource(R.color.purple_200);
                snackbar.show();
                exitTime = System.currentTimeMillis();
            } else {
                finish();
            }
            return true;
        }
        return super.dispatchKeyEvent(event);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

MainActivity作为主框架,使用ViewPager实现4个子页面Fragment的切换,使用TabLayout绑定ViewPager来切换视图,实现了Tab卡切换、ViewPager滑动页面的效果,基本实现了微信主框架的效果。

# 顶部导航条

TabLayout放在顶部的时候,加上一些属性配置,就可以完美实现顶部导航的效果。根据导航条样式,这里分为三类:

  1. 自适应非固定条数形式;
  2. 居中固定条数形式;
  3. 平铺固定条数形式。

# 自适应非固定条数

这种就是和今日头条类似的形式,适用于顶部菜单数量不固定,而且比较多的情况。

从左至右依次排放,每个菜单的内容均完全显示,长度根据内容自动伸缩,超长后的菜单需要滚动显示。

看下效果:

image-20210822114130456

为了方便,源码写在HomePageFragment中,也就是第一个子页面“微信”中。

HomePageFragment.java

public class HomePageFragment extends BaseFragment {

    private View rootView;

    private List<String> names;
    private BasePageFragmentAdapter mAdapter;
    private ViewPager mViewPager;
    private TabLayout mTabLayout;

    public HomePageFragment() {
        super();
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initData();
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        rootView = inflater.inflate(R.layout.fragment_homepage_head, null);
        initView();
        mAdapter = new BasePageFragmentAdapter(getChildFragmentManager());
        mViewPager.setAdapter(mAdapter);
        mTabLayout.setupWithViewPager(mViewPager);

        // 更新适配器数据
        mAdapter.setList(names);
        return rootView;
    }

    private void initView() {
        mViewPager = rootView.findViewById(R.id.homepage_view_pager);
        mTabLayout = rootView.findViewById(R.id.homepage_tab_layout);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

    private void initData() {
        names = new ArrayList<>();
        names.add("关注");
        names.add("推荐");
        names.add("热点");
        names.add("视频");
        names.add("小说");
        names.add("娱乐");
        names.add("问答");
        names.add("图片");
        names.add("科技");
        names.add("懂车帝");
        names.add("体育");
        names.add("财经");
        names.add("军事");
        names.add("国际");
        names.add("健康");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

这里采用的是将Fragment的标题放入到集合中,也可以在Activity初始化时传入到Fragment中,通过getTitle来获取

	@Nullable
    @Override
    public CharSequence getPageTitle(int position) {
        // 不用在主Activity添加tab标题,这里直接设置
        return container.get(position).getTitle();
    }
1
2
3
4
5
6

详情使用见Demo:https://github.com/IQQcode/MobileCoding/tree/main/Android-Base/02-UI%20Controls/c-Component/TabLayout-ViewPager/TabLayout01


fragment_homepage_head.xml

布局有主界面比较相似,不过TabLayout被放在顶部了。

【说明】:

app:tabMode=“scrollable”

tabMode的值设为scrollable,表示tab卡过多时自动滑动。

<?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=".fragment.MsgFragment">

    <android.support.design.widget.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="34dip"
        app:tabBackground="@color/white"
        app:tabIndicatorColor="@color/menu_green"
        app:tabIndicatorHeight="1dip"
        app:tabMode="scrollable"
        app:tabMinWidth="40dip"
        app:tabPaddingStart="5dip"
        app:tabPaddingEnd="5dip"
        app:tabSelectedTextColor="@color/wx_head_selected"
        app:tabTextAppearance="@style/tab_head"
        app:tabTextColor="@color/wx_head_default" />

    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="10dip"
        android:layout_weight="1"
        android:background="@color/white" />
</LinearLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 消息内容子页面适配器

BasePageFragmentAdapter.java

因为内容页大多近似,所以采用同一个Fragment布局即可,内容根据传参来修改。

public class BasePageFragmentAdapter extends FragmentPagerAdapter {

    private List<String> names;

    public BasePageFragmentAdapter(FragmentManager fm) {
        super(fm);
        this.names = new ArrayList<>();
    }

    /**
     * 数据列表
     * @param datas
     */
    public void setList(List<String> datas) {
        this.names.clear();
        this.names.addAll(datas);
        notifyDataSetChanged();
    }

    @Override
    public Fragment getItem(int position) {
        ViewContainerFragment fragment = new ViewContainerFragment();
        Bundle bundle = new Bundle();
        bundle.putString("name", names.get(position));
        fragment.setArguments(bundle);
        return fragment;
    }

    @Override
    public int getCount() {
        return names.size();
    }

    @Override
    public CharSequence getPageTitle(int position) {
        String plateName = names.get(position);
        if (plateName == null) {
            plateName = "";
        } else if (plateName.length() > 15) {
            plateName = plateName.substring(0, 15) + "...";
        }
        return plateName;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

# 消息内容页

子页面只放了一个TextView用来显示参数,ViewContainerFragment.java:

public class ViewContainerFragment extends BaseFragment {
    TextView tvContent;

    private String name;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


        Bundle bundle = getArguments();
        name = bundle.getString("name");
        if (name == null) {
            name = "参数非法";
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_msg_content, container, false);
        tvContent = view.findViewById(R.id.txt_content);
        tvContent.setText(name);
        return view;
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

页面布局fragment_msg_content.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/txt_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Hello blank fragment"
        android:textSize="18sp" />

</RelativeLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# Tablayut居中设置

# 居中固定条数

这种形式的导航栏位于水平居中位置,适用于顶部菜单数量较少的情况。

从左至右依次排放,菜单整体位于水平居中位置,因为数量较少,一般不会滚动显示。

看下效果:

img

由于界面构建原理与上述内容一致,在此仅说明不同之处:

<?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">

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/maillist_tab_layout"
        android:layout_width="match_parent"
        android:layout_height="34dip"
        android:background="@color/white"
        app:tabBackground="@color/white"
        app:tabGravity="center"
        app:tabIndicatorHeight="0dip"
        app:tabMinWidth="40dip"
        app:tabMode="fixed"
        app:tabPaddingEnd="5dip"
        app:tabPaddingStart="5dip"
        app:tabSelectedTextColor="@color/wx_head_selected"
        app:tabTextAppearance="@style/tab_head"
        app:tabTextColor="@color/wx_head_default" />

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/maillist_view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="10dip"
        android:layout_weight="1"
        android:background="@color/white" />

</LinearLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

TabLayout有两个属性与“自适应非固定条数”形式不一样:

app:tabMode=“fixed”

tabMode的值设置为fixed(默认值,也可以不加该属性),表示TabLayout的内容最大长度不会超过自身长度,也就是说不会出现滚动条,添加这个属性时,如果Tab过多,则会比较挤,出现Tab内部内容换行的情况。

app:tabGravity=“center”

tabGravity定义Tab内部的对齐方式,当该属性值为center时,表示居中对齐,不进行拉伸,根据Tab内容自适应宽度。

# 平铺固定条数

Tab平均分配宽度,适用于顶部菜单数量固定,且需要撑满页面的情况。

从左至右依次排放,菜单内容填满整个TabLayout控件,不会滚动显示。

看下效果:

img

<?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">

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/find_tab_layout"
        android:layout_width="match_parent"
        android:layout_height="34dip"
        android:background="@color/white"
        app:tabBackground="@color/white"
        app:tabGravity="fill"
        app:tabIndicatorHeight="0dip"
        app:tabMinWidth="40dip"
        app:tabMode="fixed"
        app:tabPaddingEnd="5dip"
        app:tabPaddingStart="5dip"
        app:tabSelectedTextColor="@color/wx_head_selected"
        app:tabTextAppearance="@style/tab_head"
        app:tabTextColor="@color/wx_head_default"/>

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/find_view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="10dip"
        android:layout_weight="1"
        android:background="@color/white">
    </androidx.viewpager.widget.ViewPager>
</LinearLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

TabLayout有一个属性与“居中固定条数”形式不一样:

app:tabGravity=“fill”

tabGravity定义Tab内部的对齐方式,当该属性值为fill时,表示填充宽度,会进行拉伸,根据Tab数量平均分配每个Tab的宽度。


# 总结

TabLayout的出现基本解决了以前Android开发遇到的Tab页卡效果不好、不流畅的问题,而且TabLayout还添加了Indicator,能够随手指滑动,修改起来也比较方便。

除了没有直接解决滑动过程中颜色渐变、过渡的问题,普通场景使用TabLayout这个控件已经可以满足需求了。


  • 作者:ahuyangdong (opens new window)
  • 原文链接:https://blog.csdn.net/ahuyangdong/article/details/82493158
编辑 (opens new window)
上次更新: 2022/03/27, 22:58:50
TabLayout使用详解
Tablayout属性使用全解

← TabLayout使用详解 Tablayout属性使用全解→

最近更新
01
匿名内部类
10-08
02
函数式接口
10-08
03
ARouter-Kotlin踩坑
10-05
更多文章>
Theme by Vdoing | Copyright © 2021-2023 iqqcode | MIT License | 备案号-京ICP备2021028793号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×