Google在2015年的Google IO大會上更新了Design Support Library,里面提供了幾個封裝好的MeterDesign風格控件,其中包括:
-
TextInputLayout : 使用TextInputLayout將EditText進行了封裝,提示信息會變成一個顯示在EditText之上的floating label,這樣用戶就始終知道他們現在輸入的是什么,而且過度動畫是平滑的。還可以在下方通過setError設置Error提示
這里寫圖片描述 -
FloatingActionButton : 負責顯示界面基本操作的圓形按鈕
這里寫圖片描述 -
Snackbar : 為一個操作提供輕量級、快速的反饋
這里寫圖片描述 -
TabLayout : 既實現了固定的選項卡(View的寬度平均分配),也實現了可滾動的選項卡(View寬度不固定同時可以橫向滾動)
這里寫圖片描述 NavigationView : 通過提供抽屜導航所需的框架讓實現更簡單
具體的介紹可以看看:http://android-developers.blogspot.com/2015/05/android-design-support-library.html
這篇文章里面,記錄一下TabLayout 的使用,還有幾個不得不說的坑!
先看效果:
上面是TabLayout ,下面是ViewPager,最簡單的一個demo。下面介紹一些如何實現。
首先是導入,在build.gradle 文件中加上這段代碼
compile 'com.android.support:design:23.2.0'
然后Activity的布局文件內容如下:
<?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.support.design.widget.TabLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/tabs"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
app:tabSelectedTextColor="@color/com_bg_black"
app:tabTextColor="@color/light_gray"/>
<android.support.v4.view.ViewPager
android:id="@+id/vp_view"
android:layout_below="@id/tabs"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
簡單吧!使用TabLayout中定義的屬性時需要聲明
xmlns:app="http://schemas.android.com/apk/res-auto"
上面使用到的app:tabSelectedTextColor 和 app:tabTextColor 分別是tab里選中和非選中的字體顏色,也可以在Java代碼里設置。
在activity代碼如下
public class TabLayoutActivity extends Activity {
@BindView(R.id.tabs) TabLayout mTabLayout;
@BindView(R.id.vp_view) ViewPager mViewPager;
private TextView view1, view2, view3;//頁卡視圖
private List<View> mViewList = new ArrayList<>();//頁卡視圖集合
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tabview);
ButterKnife.bind(this);
mViewPager = (ViewPager) findViewById(R.id.vp_view);
mTabLayout = (TabLayout) findViewById(R.id.tabs);
view1 = getTextView("view1");
view2 = getTextView("view2");
view3 = getTextView("view3");
//添加頁卡視圖
mViewList.add(view1);
mViewList.add(view2);
mViewList.add(view3);
mTabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);//設置tab模式,當前為系統默認模式
// mTabLayout.addTab(mTabLayout.newTab().setText(mTitleList.get(0)));//添加tab選項卡
SimplePagerAdapter mAdapter = new SimplePagerAdapter(mViewList);
mViewPager.setAdapter(mAdapter);//給ViewPager設置適配器
mTabLayout.setupWithViewPager(mViewPager);//將TabLayout和ViewPager關聯起來。
// mTabLayout.setTabsFromPagerAdapter(mAdapter);//給Tabs設置適配器
}
private TextView getTextView(String text) {
TextView textView = new TextView(this);
textView.setText(text);
textView.setGravity(Gravity.CENTER);
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return textView;
}
//ViewPager適配器
class SimplePagerAdapter extends PagerAdapter {
private List<View> mViewList;
public SimplePagerAdapter(List<View> mViewList) {
this.mViewList = mViewList;
}
@Override
public int getCount() {
return mViewList.size();//頁卡數
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;//官方推薦寫法
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(mViewList.get(position));//添加頁卡
return mViewList.get(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(mViewList.get(position));//刪除頁卡
}
@Override
public CharSequence getPageTitle(int position) {
return "Tab_" + position;//頁卡標題
}
}
}
同樣的簡潔,最終實現的效果是滑動切換viewpager時,TabLayout同步滑動切換;點擊選中TabLayout項時,viewpager自動滑動切換到對應頁面。
在xml里面,除了上面用到的兩個自定義屬性,還有一些其他的屬性,下面羅列出來:
public static final int TabLayout_tabBackground = 3;
public static final int TabLayout_tabContentStart = 2;
public static final int TabLayout_tabGravity = 5;
public static final int TabLayout_tabIndicatorColor = 0;// 設置為透明即為隱藏
public static final int TabLayout_tabIndicatorHeight = 1;
public static final int TabLayout_tabMaxWidth = 7;
public static final int TabLayout_tabMinWidth = 6;
public static final int TabLayout_tabMode = 4;
public static final int TabLayout_tabPadding = 15;
public static final int TabLayout_tabPaddingBottom = 14;
public static final int TabLayout_tabPaddingEnd = 13;
public static final int TabLayout_tabPaddingStart = 11;
public static final int TabLayout_tabPaddingTop = 12;
public static final int TabLayout_tabSelectedTextColor = 10;// 選中的文字顏色
public static final int TabLayout_tabTextAppearance = 8;// 可以設置文字大小和顏色
public static final int TabLayout_tabTextColor = 9;// 非選中狀態的文字顏色
從上面的屬性里可以看到需要設置文字大小需要通過tabTextAppearance屬性來定義,從TabLayout源碼發現,只有這一種方式設置字體大小。
并且設置文字顏色時,tabTextColor的優先級高于tabTextAppearance。
第一坑:
Caused by: java.lang.IllegalArgumentException: You need to use a Theme.AppCompat theme (or descendant) with the design library.
at android.support.design.widget.ThemeUtils.checkAppCompatTheme(ThemeUtils.java:34)
從提示上看,是說我們使用這個library里的控件時,需要把activity的style設置為Theme.AppCompat的衍生主題。我的設置如下:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
</style>
探其所以然:
ThemeUtils.java內容較少,就直接貼出來:
class ThemeUtils {
private static final int[] APPCOMPAT_CHECK_ATTRS = { R.attr.colorPrimary };
static void checkAppCompatTheme(Context context) {
TypedArray a = context.obtainStyledAttributes(APPCOMPAT_CHECK_ATTRS);
final boolean failed = !a.hasValue(0);
if (a != null) {
a.recycle();
}
if (failed) {
throw new IllegalArgumentException("You need to use a Theme.AppCompat theme "
+ "(or descendant) with the design library.");
}
}
}
看到這里,仿佛僅僅校驗R.attr.colorPrimary屬性是否存在。于是把BaseTheme改為android:Theme.Light,并添加R.attr.colorPrimary屬性(要求minSdk>=21),但是結果還是閃退,log都木有。估計是后面用到了Theme.AppCompat下面的其他屬性,不然校驗一個無用屬性也是太無厘頭了。最終,還是乖乖使用Theme.AppCompat.Light.DarkActionBar。
第二坑
上圖中的tab不見了,但是下面的指示條還在,并且點擊事件也都有。原因是沒有覆寫PagerAdapter.getPageTitle(position).
查看TabLayout的源碼發現這個:
天地良心啊,直接把我手動添加的tab全部移除了,然后自己調用PagerAdapter.getPageTitle(position)獲得標題tab。這封裝果然實用,但是不看源碼還得是被坑的團團轉!
所以:不用自己添加tab,只需要覆寫PagerAdapter.getPageTitle(position)。
第三坑
標題欄的英文字符全部轉大寫了。。。這就好尷尬了,在網上找了好幾天資料(PS:百度出來的結果都差不多),都是說要設置textAllCaps屬性:
<!--TAB文字樣式-->
<style name="MyCustomTabTextAppearance" parent="TextAppearance.Design.Tab">
<item name="textAllCaps">false</item>
</style>
然而并沒有用!查看TextAppearance.Design.Tab,發現textAllCaps默認為true,也就是全部轉大寫
最后找到解決方案后,才發現是自己看源碼時太關注屬性值了,也是眼瞎,竟沒看出來textAllCaps是自定義的一個屬性,Android內定義的屬性都是以android:開頭的,握草!
<style name="TabLayoutTextAppearance" parent="TextAppearance.Design.Tab">
<item name="textAllCaps">false</item>
<item name="android:textAllCaps">false</item>
</style>
最終是醬紫的!
好了,大坑目前就發現這幾個,總得來說TabLayout還是很好用的,如果這個效果如果夠用的話,還是用Google自家的!
再說一點:
第一個紅框標識,此處只是移除之前額外添加的滑動監聽,因為Adapter已經更換,所以PageChangeListener也需要更換。
下面的第二個紅框標出來,是想說,里面已經封裝好了不需要重復調用TabLayout.setTabsFromPagerAdapter(mAdapter),也就是我上面注釋掉的一行代碼。
源碼鏈接:https://github.com/brian512/AndroidDemo