TabLayout+ViewPager+Fragment實現頂部或底部導航欄
以前看慕課網的教程,寫過一個微信Tab選項卡切換的例子,使用的是ViewPager+Fragment來實現的,說實話,當時為了實現一些效果,還是寫了蠻多的程式碼,但是,今天介紹的TabLayout+ViewPager+Fragment實現導航欄可以使用很少的程式碼實現很棒的效果。
首先說說TabLayout,它是在Android5.0之後提出的,可以實現Material Design效果,可以方便地幫助我們實現導航欄的效果。接著說一下ViewPager,它是Android擴充套件包v4中的類,可以實現view的左右切換。Fragment就不過多介紹了,相信大家都瞭解。下面就說說具體的實現步驟:
一、實現頂部導航欄
1 . 新增所需依賴
compile 'com.android.support:appcompat-v7:24.2.0'
compile 'com.android.support:design:24.2.0'
說明:上面的第一個包我們在建立Android工程的時候一般會預設引入,他其中包含了Android support v4的包,我們此處是使用v4包中的ViewPager。下面的那個包是我們要使用其中的TabLayout。
2 . 建立對應於每個Tab選項卡的Fragment
接著我們建立對應於每個Tab的View頁面,假設你需要3個Tab,則對應建立3個Fragment檔案,並生成每個Fragment對應的佈局檔案。此處寫一個作為示例。
Fragment1.java
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment1,container, false);
}
}
fragment1.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
3 . 定義介面卡
接著我們要開始定義介面卡類,為下一步的繫結做準備。
public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
private String[] mTitles = new String[]{"Fragment1", "Fragment2"};
public HomeFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
//此處根據不同的position返回不同的Fragment
if (position == 1){
return new Fragment2();
}
return new Fragment1();
}
@Override
public int getCount() {
//此處返回Tab的數目
return mTitles.length;
}
@Override
public CharSequence getPageTitle(int position) {
//此處返回每個Tab的title
return mTitles[position];
}
}
上面的程式碼很好理解,這裡不再解釋。
4 . 建立主佈局檔案
由於我們要實現的是頂部導航欄,所有我們此處的佈局應該為上面部分是TabLayout,下面部分是ViewPager,佈局檔案如下:
<?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"
android:id="@+id/activity_role"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/colorGray">
<android.support.design.widget.TabLayout
app:tabGravity="fill"
android:id="@+id/home_tablayout"
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="@color/colorWhite"
app:tabIndicatorColor="#66ff33"
app:tabIndicatorHeight="2dp"
app:tabTextColor="@color/colorTheme"
app:tabSelectedTextColor="#CC33FF"
app:tabMode="fixed"
app:tabBackground="@drawable/tablayout_selector"
app:tabTextAppearance="@style/TabLayoutTextAppearance">
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:id="@+id/home_viewpager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</android.support.v4.view.ViewPager>
</LinearLayout>
上面ViewPager的使用沒什麼好說的,主要是說說TabLayout的一些屬性:
屬性 | 作用 |
---|---|
tabGravity | fill 多個tab會平分TabLayout來顯示 / center 多個tab會按實際大小在TabLayout上居中顯示 |
tabIndicatorColor | tab上面指示器的顏色 |
tabIndicatorHeight | tab上面指示器的高度 |
tabTextColor | tab上面顯示的字型的顏色 |
tabSelectedTextColor | tab被選中時字型的顏色 |
tabMode | fixed TabLayout上多個tab是固定的 / scrollable 多個tab時,tab是可以滾動的 |
注意:這是我踩過的一個坑,當時我把 tabMode設定為scrollable,然後發現tabGravity設定為fill,可是tab還是不能平分TabL,後來才知道,只有tabMode設定為fixed時,tabGravity設定為fill才會生效。
上面的tabBackground我是使用自定義的一個selector實現tab在選中和未選中狀態的背景顏色,下面是程式碼
tablayout_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true"
android:drawable="@color/colorTheme"/>
<item android:drawable="@color/colorGray"/>
</selector>
tabTextAppearance屬性是自己簡單定義的一個文字樣式,主要是設定字型大小及顏色,下面是程式碼:
style.xml檔案
<style name="TabLayoutTextAppearance" parent="TextAppearance.AppCompat.Widget.ActionBar.Title">
<item name="android:textSize">15sp</item>
<item name="android:textColor">@color/colorTextGray</item>
</style>
5 . 在MainActivity中繫結佈局
private TabLayout mTabLayout;
private ViewPager mViewPager;
private MyFragmentPagerAdapter mFragmentPagerAdapter;
private TabLayout.Tab mTab1;
private TabLayout.Tab mTab2;
mViewPager = (ViewPager) findViewById(R.id.m_viewpager);
mFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
//給ViewPager設定介面卡
mViewPager.setAdapter(mFragmentPagerAdapter);
//tablayout與Viewpager繫結
mTabLayout = (TabLayout) findViewById(R.id.m_tablayout);
mTabLayout.setupWithViewPager(mViewPager);
mTab1 = mTabLayout.getTabAt(0);
mTab = mTabLayout.getTabAt(1);
通過上面的設定,就可以實現頂部導航欄啦。
下面放上一個效果圖:
二、實現底部導航欄
其實,底部導航欄非常好實現,我們只需要在佈局檔案中,將上面的部分放置ViewPager,下面的部分放置TabLayout即可,其他內容不變。或許我們有時候需要在底部導航欄加入小圖示,那我們就可以在上面的基礎上通過以下程式碼進行設定:
mTab1.setIcon(R.drawable.ic_1);
mTab2.setIcon(R.drawable.ic_2);
有時候我們可能並不希望我們的ViewPager是可滑動切換的,只希望它可以點選切換,那我們可以通過自定義ViewPager,同時讓其不再攔截觸控事件即可,程式碼如下:
public class DisabledTouchViewPager extends ViewPager {
//true為允許滑動手勢
private boolean enable = false;
public DisabledTouchViewPager(Context context) {
super(context);
}
public DisabledTouchViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return enable;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return enable;
}
}
然後將xml檔案中的ViewPager換成我們自定義的ViewPager即可。記得必須使用自定義ViewPager的完整路徑。