前言
TabLayout
是5.0版本出现的控件,显示水平方向的tab
页。需要添加Design
依赖库,并且使用Theme.AppCompat
主题。
1. TabLayout类
布局文件
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:background="@color/white"/>
利用addTab(Tab)
和newTab()
方法添加tab页
TabLayout tabLayout = findViewById(R.id.tab_layout1);
tabLayout.addTab(tabLayout.newTab().setText("tab1"));
tabLayout.addTab(tabLayout.newTab().setText("tab2"));
tabLayout.addTab(tabLayout.newTab().setText("tab3"));
效果如下
2. 主要参数
3. TabLayout主要方法
-
addTab(Tab)
,向此布局添加选项卡
-
addView(View)
,添加子视图
-
addOnTabSelectedListener(OnTabSelectedListener)
,添加监听器
-
newTab()
,创建一个新的tab
-
setTabTextColors(int, int)
,设置用于选项卡的不同状态的文本颜色
-
setSelectedTabIndicatorColor(int)
,设置选中的tab
的指示器颜色
-
setSelectedTabIndicatorHeight(int)
,设置选中的tab
的指示器的高度
-
setTabGravity(int)
,设置TabLayout
的布局方式
-
setTabMode(int)
,设置tab
选项卡的行为模式
-
setupWithViewPager(ViewPager, boolean)
,将TabLayout
与ViewPager
绑定在一起
4. 自定义TabItem
在配置文件中指定TabItem
<android.support.design.widget.TabLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:background="@color/white">
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="tab1"/>
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="tab2"
android:icon="@mipmap/ic_launcher"/>
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/layout_tab_item1"/>
</android.support.design.widget.TabLayout>
layout_tab_item1.xml
文件
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="tab4"
android:gravity="center"/>
调用Tab.setCustomView(int)
方法
tabLayout.addTab(tabLayout.newTab().setCustomView(R.layout.layout_tab_item2));
效果如下
5. TabLayout代码分析
TabLayout.newTab()
方法
public Tab newTab() {
// sTabPool是一个数据池,保存Tab
Tab tab = sTabPool.acquire();
if (tab == null) {
tab = new Tab();
}
tab.mParent = this;
// createTabView 方法创建一个`TabView`
tab.mView = createTabView(tab);
return tab;
}
private TabView createTabView(@NonNull final Tab tab) {
// mTabViewPool同样是个数据池,用来保存TabView
TabView tabView = mTabViewPool != null ? mTabViewPool.acquire() : null;
if (tabView == null) {
tabView = new TabView(getContext());
}
// 设置tab内容
tabView.setTab(tab);
tabView.setFocusable(true);
tabView.setMinimumWidth(getTabMinWidth());
return tabView;
}
TabView
继承LinearLayout
public TabView(Context context) {
super(context);
if (mTabBackgroundResId != 0) {
ViewCompat.setBackground(
this, AppCompatResources.getDrawable(context, mTabBackgroundResId));
}
ViewCompat.setPaddingRelative(this, mTabPaddingStart, mTabPaddingTop,
mTabPaddingEnd, mTabPaddingBottom);
setGravity(Gravity.CENTER);
setOrientation(VERTICAL);
setClickable(true);
ViewCompat.setPointerIcon(this,
PointerIconCompat.getSystemIcon(getContext(), PointerIconCompat.TYPE_HAND));
}
void setTab(@Nullable final Tab tab) {
if (tab != mTab) {
mTab = tab;
update();
}
}
final void update() {
final Tab tab = mTab;
// 是否是自定义View
final View custom = tab != null ? tab.getCustomView() : null;
if (custom != null) {
final ViewParent customParent = custom.getParent();
if (customParent != this) {
if (customParent != null) {
((ViewGroup) customParent).removeView(custom);
}
addView(custom);
}
mCustomView = custom;
// 设置默认不可见
if (mTextView != null) {
mTextView.setVisibility(GONE);
}
if (mIconView != null) {
mIconView.setVisibility(GONE);
mIconView.setImageDrawable(null);
}
mCustomTextView = (TextView) custom.findViewById(android.R.id.text1);
if (mCustomTextView != null) {
mDefaultMaxLines = TextViewCompat.getMaxLines(mCustomTextView);
}
mCustomIconView = (ImageView) custom.findViewById(android.R.id.icon);
} else {
// We do not have a custom view. Remove one if it already exists
if (mCustomView != null) {
removeView(mCustomView);
mCustomView = null;
}
mCustomTextView = null;
mCustomIconView = null;
}
// 如果没有自定义View,使用默认ImageView和TextView
if (mCustomView == null) {
// If there isn't a custom view, we'll us our own in-built layouts
if (mIconView == null) {
ImageView iconView = (ImageView) LayoutInflater.from(getContext())
.inflate(R.layout.design_layout_tab_icon, this, false);
addView(iconView, 0);
mIconView = iconView;
}
if (mTextView == null) {
TextView textView = (TextView) LayoutInflater.from(getContext())
.inflate(R.layout.design_layout_tab_text, this, false);
addView(textView);
mTextView = textView;
mDefaultMaxLines = TextViewCompat.getMaxLines(mTextView);
}
TextViewCompat.setTextAppearance(mTextView, mTabTextAppearance);
if (mTabTextColors != null) {
mTextView.setTextColor(mTabTextColors);
}
updateTextAndIcon(mTextView, mIconView);
} else {
// Else, we'll see if there is a TextView or ImageView present and update them
if (mCustomTextView != null || mCustomIconView != null) {
updateTextAndIcon(mCustomTextView, mCustomIconView);
}
}
// Finally update our selected state
setSelected(tab != null && tab.isSelected());
}
TabLayout.addTab(Tab, int, boolean)
方法
public void addTab(@NonNull Tab tab, int position, boolean setSelected) {
if (tab.mParent != this) {
throw new IllegalArgumentException("Tab belongs to a different TabLayout.");
}
configureTab(tab, position);
addTabView(tab);
if (setSelected) {
tab.select();
}
}
// 配置Tab
private void configureTab(Tab tab, int position) {
tab.setPosition(position);
mTabs.add(position, tab);
final int count = mTabs.size();
for (int i = position + 1; i < count; i++) {
mTabs.get(i).setPosition(i);
}
}
private void addTabView(Tab tab) {
final TabView tabView = tab.mView;
mTabStrip.addView(tabView, tab.getPosition(), createLayoutParamsForTabs());
}
TabLayout.addView(View)
方法会调用addViewInternal(View)
方法,child
必须是TabItem
类型。
private void addViewInternal(final View child) {
if (child instanceof TabItem) {
addTabFromItemView((TabItem) child);
} else {
throw new IllegalArgumentException("Only TabItem instances can be added to TabLayout");
}
}
private void addTabFromItemView(@NonNull TabItem item) {
final Tab tab = newTab();
if (item.mText != null) {
// 会调用TabView.update修改
tab.setText(item.mText);
}
if (item.mIcon != null) {
// 会调用TabView.update修改
tab.setIcon(item.mIcon);
}
if (item.mCustomLayout != 0) {
// 会调用TabView.update修改
tab.setCustomView(item.mCustomLayout);
}
if (!TextUtils.isEmpty(item.getContentDescription())) {
tab.setContentDescription(item.getContentDescription());
}
addTab(tab);
}
TabItem
类,可以指定text
和icon
,也可以自定义layout
。
public final class TabItem extends View {
final CharSequence mText;
final Drawable mIcon;
final int mCustomLayout;
public TabItem(Context context) {
this(context, null);
}
public TabItem(Context context, AttributeSet attrs) {
super(context, attrs);
final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
R.styleable.TabItem);
mText = a.getText(R.styleable.TabItem_android_text);
mIcon = a.getDrawable(R.styleable.TabItem_android_icon);
mCustomLayout = a.getResourceId(R.styleable.TabItem_android_layout, 0);
a.recycle();
}
}