相关文章
Android Snackbar控件
Android FloatingActionButton控件
Android Toolbar控件
Android AppBarLayout控件
Android CollapsingToolbarLayout控件
Android CardView控件
Android SlidingPaneLayout和DrawerLayout控件
Android TabLayout控件
前言
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()
和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. 主要参数
-
tabSelectedTextColor,改变选中字体的颜色
-
tabTextColor,未选中字体的颜色
-
tabTextAppearance,字体大小
app:tabSelectedTextColor="#FFFF8800" app:tabTextColor="#FFCCCCCC" app:tabTextAppearance="@style/tabLayoutTextAppearance"
效果如下
-
tabIndicatorColor,指示器下标的颜色
-
tabIndicatorHeight,指示器下标的高度
app:tabIndicatorColor="#FFFF8800" app:tabIndicatorHeight="4dp"
效果如下
-
tabGravity,内容显示方式
center(内容居中显示)
和fill(内容尽可能充满)
效果如下
-
tabMode,tab选项卡的行为模式,
fixed(tab固定)
和scrollable(tab可滑动)
效果如下
-
tabBackground,背景
-
tabContentStart,相对起始位置tab的Y轴偏移量
-
tabPadding,tab的内边距
-
tabPaddingStart,tab的左侧内边距
-
tabPaddingEnd,tab的右侧内边距
-
tabPaddingTop,tab的顶部内边距
-
tabPaddingBottom,tab的底部内边距
-
tabMaxWidth,tab选项卡的最大宽度
-
tabMinWidth,tab选项卡的最小宽度
3. TabLayout主要方法
- addTab,向此布局添加选项卡
- addView,添加子视图
- addOnTabSelectedListener,添加监听器
- newTab,创建一个新的tab
- setTabTextColors,设置用于选项卡的不同状态的文本颜色
- setSelectedTabIndicatorColor,设置选中的tab的指示器颜色
- setSelectedTabIndicatorHeight,设置选中的tab的指示器的高度
- setTabGravity,设置TabLayout的布局方式
- setTabMode,设置tab选项卡的行为模式
- setupWithViewPager,将TabLayout与ViewPager链接在一起
4. 自定义控件
-
在配置文件中指定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>
-
调用
Tab.setCustomView
方法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方法
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方法会调用
addViewInternal
方法,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(); } }