轉 android design library提供的TabLayout的用法
原文出處:http://chenfuduo.me/2015/07/30/TabLayout-of-design-support-library/
在開發中,我們常常需要ViewPager結合Fragment一起使用,如下圖:
1
我們可以使用三方開源的PagerSlidingTabStrip去實現,或者viewpagerindicator,我一般都偏向前者。現在我們可以使用Design support library庫的TabLayout去實現了。最終的效果圖:
效果圖
建立佈局
<?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!--app:tabMode="scrollable"這個屬性我在程式碼中設定了--> <!--tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);--> <android.support.design.widget.TabLayout android:id="@+id/sliding_tabs" android:layout_width="match_parent" android:layout_height="wrap_content" /> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="0px" android:layout_weight="1" android:background="@android:color/white"/> </LinearLayout> 在xml新增TabLayout,如同ViewPager,直接`android.support.design.widget.TabLayout`即可。還有其他的屬性我會在程式碼中設定。 |
建立Fragment
packageme.chenfuduo.myfragmentdemo.fragment; importandroid.os.Bundle; importandroid.support.annotation.Nullable; importandroid.support.v4.app.Fragment; importandroid.view.LayoutInflater; importandroid.view.View; importandroid.view.ViewGroup; importandroid.widget.TextView; importme.chenfuduo.myfragmentdemo.R; /** *CreatedbyAdministratoron2015/7/30. */ publicclassPageFragmentextendsFragment{ publicstaticfinalStringARG_PAGE="ARG_PAGE"; privateintmPage; publicstaticPageFragmentnewInstance(intpage){ Bundleargs=newBundle(); args.putInt(ARG_PAGE,page); PageFragmentpageFragment=newPageFragment(); pageFragment.setArguments(args); returnpageFragment; } @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); mPage=getArguments().getInt(ARG_PAGE); } @Nullable @Override publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){ Viewview=inflater.inflate(R.layout.fragment_page,container,false); TextViewtextView=(TextView)view; textView.setText("Fragment#"+mPage); returnview; } } |
其中Fragment的佈局為:
<?xmlversion="1.0"encoding="utf-8"?> <TextViewxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center"/> |
ViewPager的介面卡
packageme.chenfuduo.myfragmentdemo.adapter; importandroid.content.Context; importandroid.support.v4.app.Fragment; importandroid.support.v4.app.FragmentManager; importandroid.support.v4.app.FragmentPagerAdapter; importme.chenfuduo.myfragmentdemo.fragment.PageFragment; /** *CreatedbyAdministratoron2015/7/30. */ publicclassSimpleFragmentPagerAdapterextendsFragmentPagerAdapter{ finalintPAGE_COUNT=3; privateStringtabTitles[]=newString[]{"tab1","tab2","tab3"}; privateContextcontext; publicSimpleFragmentPagerAdapter(FragmentManagerfm,Contextcontext){ super(fm); this.context=context; } @Override publicFragmentgetItem(intposition){ returnPageFragment.newInstance(position+1); } @Override publicintgetCount(){ returnPAGE_COUNT; } @Override publicCharSequencegetPageTitle(intposition){ returntabTitles[position]; } } |
設定TabLayout
packageme.chenfuduo.myfragmentdemo; importandroid.os.Bundle; importandroid.support.design.widget.TabLayout; importandroid.support.v4.app.FragmentActivity; importandroid.support.v4.view.ViewPager; importandroid.view.Menu; importandroid.view.MenuItem; importme.chenfuduo.myfragmentdemo.adapter.SimpleFragmentPagerAdapter; publicclassThirdActivityextendsFragmentActivity{ privateSimpleFragmentPagerAdapterpagerAdapter; privateViewPagerviewPager; privateTabLayouttabLayout; @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_third); pagerAdapter=newSimpleFragmentPagerAdapter(getSupportFragmentManager(),this); viewPager=(ViewPager)findViewById(R.id.viewpager); viewPager.setAdapter(pagerAdapter); tabLayout=(TabLayout)findViewById(R.id.sliding_tabs); tabLayout.setupWithViewPager(viewPager); tabLayout.setTabMode(TabLayout.MODE_FIXED); } } |
這裡提幾點我遇到的問題
tabLayout.setTabMode(TabLayout.MODE_FIXED);
開始我設定的是:
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE); |
執行後,三個TabLayout標籤擠到一塊去了。如下:
檢視api,找到結果了。這個tabmode有兩個屬性值:
MODE_FIXED:Fixed tabs display all tabs concurrently and are best used with content that benefits from quick pivots between tabs.
MODE_SCROLLABLE:Scrollable tabs display a subset of tabs at any given moment, and can contain longer tab labels and a larger number of tabs.
不做過多的解釋,MODE_SCROLLABLE適合很多tabs的情況。
setupWithViewPager必須在ViewPager.setAdapter()之後呼叫
檢視下原始碼就知道了:
publicvoidsetupWithViewPager(ViewPagerviewPager){ PagerAdapteradapter=viewPager.getAdapter(); if(adapter==null){ thrownewIllegalArgumentException("ViewPagerdoesnothaveaPagerAdapterset"); }else{ ... } } |
以上就是最基本的用法,是不是很簡單。哈~
定義TabLayout的樣式
預設的情況下,TabLayout的tab indicator的顏色是Material Design中的accent color(#009688),我們可以稍作修改:
<stylename="MyCustomTabLayout"parent="Widget.Design.TabLayout"> <itemname="tabIndicatorColor">#0000FF</item> </style> |
在佈局中使用:
<android.support.design.widget.TabLayout android:id="@+id/sliding_tabs" style="@style/MyCustomTabLayout" android:layout_width="match_parent" android:layout_height="wrap_content" /> |
還有一些其他的樣式可供選擇:
<stylename="MyCustomTabLayout"parent="Widget.Design.TabLayout"> <itemname="tabMaxWidth">@dimen/tab_max_width</item> <itemname="tabIndicatorColor">?attr/colorAccent</item> <itemname="tabIndicatorHeight">2dp</item> <itemname="tabPaddingStart">12dp</item> <itemname="tabPaddingEnd">12dp</item> <itemname="tabBackground">?attr/selectableItemBackground</item> <itemname="tabTextAppearance">@style/MyCustomTabTextAppearance</item> <itemname="tabSelectedTextColor">?android:textColorPrimary</item> </style> <stylename="MyCustomTabTextAppearance"parent="TextAppearance.Design.Tab"> <itemname="android:textSize">14sp</item> <itemname="android:textColor">?android:textColorSecondary</item> <itemname="textAllCaps">true</item> </style> |
新增icon到tab
當前的TabLayout沒有方法讓我們去新增icon,我們可以使用SpannableString結合ImageSpan來實現,在SimpleFragmentPagerAdapter中:
privateint[]imageResId={ R.drawable.ic_one, R.drawable.ic_two, R.drawable.ic_three }; //... @Override publicCharSequencegetPageTitle(intposition){ //Generatetitlebasedonitemposition //returntabTitles[position]; Drawableimage=context.getResources().getDrawable(imageResId[position]); image.setBounds(0,0,image.getIntrinsicWidth(),image.getIntrinsicHeight()); SpannableStringsb=newSpannableString(""); ImageSpanimageSpan=newImageSpan(image,ImageSpan.ALIGN_BOTTOM); sb.setSpan(imageSpan,0,1,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); returnsb; } |
執行,發現沒有顯示,這是因為TabLayout建立的tab預設設定textAllCaps屬性為true,這阻止了ImageSpan被渲染出來,可以通過下面的樣式檔案定義來改變:
<stylename="MyCustomTabLayout"parent="Widget.Design.TabLayout"> <itemname="tabTextAppearance">@style/MyCustomTextAppearance</item> </style> <stylename="MyCustomTextAppearance"parent="TextAppearance.Design.Tab"> <itemname="textAllCaps">false</item> </style> |
現在執行,效果就出來了。
新增icon和text到tab
@Override publicCharSequencegetPageTitle(intposition){ //Generatetitlebasedonitemposition Drawableimage=context.getResources().getDrawable(imageResId[position]); image.setBounds(0,0,image.getIntrinsicWidth(),image.getIntrinsicHeight()); //Replaceblankspaceswithimageicon SpannableStringsb=newSpannableString(""+tabTitles[position]); ImageSpanimageSpan=newImageSpan(image,ImageSpan.ALIGN_BOTTOM); sb.setSpan(imageSpan,0,1,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); returnsb; } |
我們看到在例項化SpannableString的時候,我在tabTitles[position]前面加了幾個空格,這些空格的位置是用來放置icon的。
新增自定義的view到tab
介面卡中增加getTabView(...)方法:
packageme.chenfuduo.myfragmentdemo.adapter; importandroid.content.Context; importandroid.support.v4.app.Fragment; importandroid.support.v4.app.FragmentManager; importandroid.support.v4.app.FragmentPagerAdapter; importandroid.view.LayoutInflater; importandroid.view.View; importandroid.widget.ImageView; importandroid.widget.TextView; importme.chenfuduo.myfragmentdemo.R; importme.chenfuduo.myfragmentdemo.fragment.PageFragment; /** *CreatedbyAdministratoron2015/7/30. */ publicclassSimpleFragmentPagerAdapterextendsFragmentPagerAdapter{ finalintPAGE_COUNT=3; privateStringtabTitles[]=newString[]{"tab1","tab2","tab3"}; privateint[]imageResId={R.drawable.avatar_enterprise_vip, R.drawable.avatar_grassroot, R.drawable.avatar_vip}; privateContextcontext; publicSimpleFragmentPagerAdapter(FragmentManagerfm,Contextcontext){ super(fm); this.context=context; } @Override publicFragmentgetItem(intposition){ returnPageFragment.newInstance(position+1); } @Override publicintgetCount(){ returnPAGE_COUNT; } @Override publicCharSequencegetPageTitle(intposition){ //第一次的程式碼 //returntabTitles[position]; //第二次的程式碼 /** Drawableimage=context.getResources().getDrawable(imageResId[position]); image.setBounds(0,0,image.getIntrinsicWidth(),image.getIntrinsicHeight()); SpannableStringsb=newSpannableString(""+tabTitles[position]); ImageSpanimageSpan=newImageSpan(image,ImageSpan.ALIGN_BOTTOM); sb.setSpan(imageSpan,0,1,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); returnsb;*/ returnnull; } publicViewgetTabView(intposition){ Viewview=LayoutInflater.from(context).inflate(R.layout.tab_item,null); TextViewtv=(TextView)view.findViewById(R.id.textView); tv.setText(tabTitles[position]); ImageViewimg=(ImageView)view.findViewById(R.id.imageView); img.setImageResource(imageResId[position]); returnview; } } |
簡單的佈局:
<?xmlversion="1.0"encoding="utf-8"?> <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView" android:layout_centerVertical="true" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/imageView" android:layout_centerVertical="true" android:id="@+id/textView" android:layout_marginLeft="3dp" /> </RelativeLayout> |
使用:
@Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_third); pagerAdapter=newSimpleFragmentPagerAdapter(getSupportFragmentManager(),this); viewPager=(ViewPager)findViewById(R.id.viewpager); viewPager.setAdapter(pagerAdapter); tabLayout=(TabLayout)findViewById(R.id.sliding_tabs); tabLayout.setupWithViewPager(viewPager); tabLayout.setTabMode(TabLayout.MODE_FIXED); for(inti=0;i<tabLayout.getTabCount();i++){ TabLayout.Tabtab=tabLayout.getTabAt(i); tab.setCustomView(pagerAdapter.getTabView(i)); } } |
處理配置改變
當螢幕旋轉或者配置改變的時候,我們需要儲存當前的狀態。
@Override publicvoidonSaveInstanceState(BundleoutState){ super.onSaveInstanceState(outState); outState.putInt(POSITION,tabLayout.getSelectedTabPosition()); } @Override protectedvoidonRestoreInstanceState(BundlesavedInstanceState){ super.onRestoreInstanceState(savedInstanceState); viewPager.setCurrentItem(savedInstanceState.getInt(POSITION)); } |
需要注意的是getSelectedTabPosition()方法是最新的design support library才有的。
最後的效果如下: