在build.gradle中添加依赖
dependencies {
...
implementation 'com.android.support:design:27.1.1'
}
编写布局文件activity_tab_layout.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=".TabLayoutActivity">
<FrameLayout
android:id="@+id/fragment_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</FrameLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/colorGray" />
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabBackground="@android:color/transparent"
app:tabIndicatorHeight="0dp"
app:tabSelectedTextColor="@color/colorOrangeRed"
app:tabTextAppearance="@style/TabLayoutTextStyle"
app:tabTextColor="@color/colorGray">
</android.support.design.widget.TabLayout>
</LinearLayout>
部分属性说明:
- tabBackground:tab背景,当设置为@android:color/transparent时可消去掉tab点击时出现的涟漪阴影效果
- tabIndicatorHeight:指示器(底部的下划线)的高度,当设置为0dp时,则不显示指示器
- tabSelectedTextColor:tab被选中时的文字颜色
- tabTextAppearance:可以用来控制tab中文字的大小、字体等
- tabTextColor:tab未被选中时的文字颜色
- tabIndicator:设置指示器,当设置为@null时则不显示指示器(API 28版本以后才有的属性)
- tabRippleColor:设置涟漪效果颜色,设置为@android:color/transparent时无涟漪效果(API 28版本以后才有的属性)
关于TabLayoutTextStyle代码如下
<style name="TabLayoutTextStyle">
<item name="android:textSize">18sp</item>
</style>
如果不设置文字大小的话,通过TabLayout的源码我们可以找到其默认的文字大小为14sp,图片与文字的间距为8dp(这个间距无法通过设置其它属性来设置,除非我们自定义一个TabLayout)。贴出这一块的部分关键源码:
public TabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
......
mTabTextAppearance = a.getResourceId(R.styleable.TabLayout_tabTextAppearance,
R.style.TextAppearance_Design_Tab);
......
}
可以看出当我们设置了tabTextAppearance属性时,则会使用我们设置的,否则使用默认的TextAppearance_Design_Tab,我们再去资源文件中找到该样式设置
<dimen name="design_tab_text_size">14sp</dimen>
<style name="TextAppearance.Design.Tab" parent="TextAppearance.AppCompat.Button">
<item name="android:textSize">@dimen/design_tab_text_size</item>
<item name="android:textColor">?android:textColorSecondary</item>
<item name="textAllCaps">true</item>
</style>
通过这样分析,我们又有了另外一种方法来设置文字的大小等属性,那就是在我们自己的style.xml文件中重新设置TextAppearance.Design.Tab。
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="TextAppearance.Design.Tab" parent="TextAppearance.AppCompat.Button">
<item name="android:textSize">10sp</item>
<item name="android:textColor">@color/colorPrimary</item>
<item name="textAllCaps">true</item>
</style>
</resources>
需要注意的是:tabTextColor的优先级大于tabTextAppearance中的android:textColor。
编写TabLayoutActivity代码
package com.matrix.navigation;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.design.widget.TabLayout.OnTabSelectedListener;
import android.support.design.widget.TabLayout.Tab;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import com.matrix.navigation.fragment.CaseFragment;
import com.matrix.navigation.fragment.ClassificationFragment;
import com.matrix.navigation.fragment.HomeFragment;
import com.matrix.navigation.fragment.SettingFragment;
/**
* <p> 描述:TabLayout--使用系统默认的tab布局</p>
* <p> 作者:xc </p>
* <p> 时间:3/18 2019 </p>
*/
public class TabLayoutActivity extends AppCompatActivity {
private TabLayout mTabLayout;
private Fragment mHomeFragment = new HomeFragment();
private Fragment mClassificationFragment = new ClassificationFragment();
private Fragment mCaseFragment = new CaseFragment();
private Fragment mSettingFragment = new SettingFragment();
private Fragment[] mFragments = new Fragment[]{mHomeFragment, mClassificationFragment,
mCaseFragment, mSettingFragment};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tab_layout);
initTabLayout();
// 默认选中的tab
mTabLayout.getTabAt(0).select();
}
/**
* 初始化TabLayout
*/
private void initTabLayout() {
mTabLayout = findViewById(R.id.tab_layout);
mTabLayout.addOnTabSelectedListener(new OnTabSelectedListener() {
@Override
public void onTabSelected(Tab tab) {
int position = tab.getPosition();
switchFragment(position);
}
@Override
public void onTabUnselected(Tab tab) {
}
@Override
public void onTabReselected(Tab tab) {
}
});
// 先addTab的话,如果默认设置选中0索引的话,onTabSelected方法不会执行
mTabLayout.addTab(mTabLayout.newTab().setIcon(R.drawable.tab_home_selector).setText("首页"));
mTabLayout.addTab(mTabLayout.newTab().setIcon(R.drawable.tab_classification_selector).setText("分类"));
mTabLayout.addTab(mTabLayout.newTab().setIcon(R.drawable.tab_case_selector).setText("案例"));
mTabLayout.addTab(mTabLayout.newTab().setIcon(R.drawable.tab_setting_selector).setText("设置"));
}
/**
* 切换fragment
*
* @param position
*/
private void switchFragment(int position) {
Fragment currentFragment = mFragments[position];
if (currentFragment != null) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_content, currentFragment).commit();
}
}
}
关于图片的改变通过selector来完成,以tab_home_selector为例(ps:一定要用android:state_selected属性哦):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_home_selected" android:state_selected="true" />
<item android:drawable="@drawable/ic_home_common" android:state_selected="false" />
</selector>
至此,基本代码完成,跑起来看看效果。
你会发现不管你怎么设置文字的大小,整个tab的高度是不变的,这是为什么呢?继续看源码
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// If we have a MeasureSpec which allows us to decide our height, try and use the default
// height
final int idealHeight = dpToPx(getDefaultHeight()) + getPaddingTop() + getPaddingBottom();
......
}
private int getDefaultHeight() {
boolean hasIconAndText = false;
for (int i = 0, count = mTabs.size(); i < count; i++) {
Tab tab = mTabs.get(i);
if (tab != null && tab.getIcon() != null && !TextUtils.isEmpty(tab.getText())) {
hasIconAndText = true;
break;
}
}
return hasIconAndText ? DEFAULT_HEIGHT_WITH_TEXT_ICON : DEFAULT_HEIGHT;
}
private static final int DEFAULT_HEIGHT_WITH_TEXT_ICON = 72; // dps
private static final int DEFAULT_HEIGHT = 48; // dps
完了完了,被写死了。有图片时高度为72dp(PS:图片大小也写死了24x24dp),没图片高度是48dp,想要改怎么办?改源码吗?这个方法虽然是可以的,但不可取,我们有另外的方法来解决——使用自定的tab view。
自定义view文件item_tab.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">
<ImageView
android:id="@+id/tab_image"
android:layout_width="20dp"
android:layout_height="20dp" />
<TextView
android:id="@+id/tab_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/tab_text_color_selector"
android:textSize="12sp" />
</LinearLayout>
tab_text_color_selector.xml(ps:一定要用android:state_selected属性哦)如下:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/colorOrangeRed" android:state_selected="true" />
<item android:color="@color/colorGray" android:state_selected="false"/>
</selector>
修改activity代码
package com.matrix.navigation;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.design.widget.TabLayout.OnTabSelectedListener;
import android.support.design.widget.TabLayout.Tab;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.matrix.navigation.fragment.CaseFragment;
import com.matrix.navigation.fragment.ClassificationFragment;
import com.matrix.navigation.fragment.HomeFragment;
import com.matrix.navigation.fragment.SettingFragment;
/**
* <p> 描述:TabLayout--自定义tab实现底部导航栏</p>
* <p> 作者:xc </p>
* <p> 时间:3/13 2019 </p>
*/
public class TabLayoutActivity extends AppCompatActivity {
private Fragment mHomeFragment = new HomeFragment();
private Fragment mClassificationFragment = new ClassificationFragment();
private Fragment mCaseFragment = new CaseFragment();
private Fragment mSettingFragment = new SettingFragment();
private Fragment[] mFragments = new Fragment[]{mHomeFragment, mClassificationFragment,
mCaseFragment, mSettingFragment};
private String[] tabs = new String[]{"首页", "分类", "案例", "设置"};
private int[] selectorImg = new int[]{R.drawable.tab_home_selector, R.drawable.tab_classification_selector,
R.drawable.tab_case_selector, R.drawable.tab_setting_selector};
private TabLayout mTabLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tab_layout);
initTabLayout();
// 默认选中的tab
mTabLayout.getTabAt(0).select();
}
/**
* 初始化TabLayout
*/
private void initTabLayout() {
mTabLayout = findViewById(R.id.tab_layout);
mTabLayout.addOnTabSelectedListener(new OnTabSelectedListener() {
@Override
public void onTabSelected(Tab tab) {
switchFragment(tab.getPosition());
}
@Override
public void onTabUnselected(Tab tab) {
}
@Override
public void onTabReselected(Tab tab) {
}
});
// 添加tab到容器中
for (int i = 0; i < 4; i++) {
mTabLayout.addTab(mTabLayout.newTab().setCustomView(getTabView(i)));
}
}
/**
* 切换fragment
*
* @param position
*/
private void switchFragment(int position) {
Fragment currentFragment = mFragments[position];
if (currentFragment != null) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_content, currentFragment).commit();
}
}
/**
* 设置自定义view
*
* @param index 索引值
* @return view对象
*/
private View getTabView(int index) {
View inflate = LayoutInflater.from(TabLayoutActivity.this).inflate(R.layout.item_tab, null);
ImageView tabImage = inflate.findViewById(R.id.tab_image);
TextView tabTitle = inflate.findViewById(R.id.tab_title);
tabImage.setImageResource(selectorImg[index]);
tabTitle.setText(tabs[index]);
return inflate;
}
}
看下效果图
还不错,可以自由控制文字、图片大小,以及它们的间距了。