效果
Android 底部導航欄 (底部 Tab) 最佳實踐
要實作這樣一個底部導航欄,大家最容易想到的當然就是TabLayout,Tab 切換嘛,TabLayout 就是專門幹這個事的,不過TabLayout 預設是帶有Indicator的,我們是不需要的,是以需要把它去掉,看一下布局檔案:
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/home_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
>
</FrameLayout>
<View android:layout_width="match_parent"
android:layout_height="0.5dp"
android:alpha="0.6"
android:background="@android:color/darker_gray"
/>
<android.support.design.widget.TabLayout
android:id="@+id/bottom_tab_layout"
android:layout_width="match_parent"
app:tabIndicatorHeight="0dp"
app:tabSelectedTextColor="@android:color/black"
app:tabTextColor="@android:color/darker_gray"
android:layout_height="50dp">
</android.support.design.widget.TabLayout>
</LinearLayout>
整個布局分為三個部分,最上面是一個Framelayout 用做裝Fragment 的容器,接着有一根分割線,最下面就是我們的TabLayout,去掉預設的Indicator直接設定app:tabIndicatorHeight屬性的值為0就行了。
布局檔案寫好之後,接下來看一下Activity的代碼:
public class BottomTabLayoutActivity extends AppCompatActivity {
private TabLayout mTabLayout;
private Fragment []mFragmensts;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bottom_tab_layout_ac);
mFragmensts = DataGenerator.getFragments("TabLayout Tab");
initView();
}
private void initView() {
mTabLayout = (TabLayout) findViewById(R.id.bottom_tab_layout);
mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
onTabItemSelected(tab.getPosition());
//改變Tab 狀态
for(int i=;i< mTabLayout.getTabCount();i++){
if(i == tab.getPosition()){
mTabLayout.getTabAt(i).setIcon(getResources().getDrawable(DataGenerator.mTabResPressed[i]));
}else{
mTabLayout.getTabAt(i).setIcon(getResources().getDrawable(DataGenerator.mTabRes[i]));
}
}
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
mTabLayout.addTab(mTabLayout.newTab().setIcon(getResources().getDrawable(R.drawable.tab_home_selector)).setText(DataGenerator.mTabTitle[]));
mTabLayout.addTab(mTabLayout.newTab().setIcon(getResources().getDrawable(R.drawable.tab_discovery_selector)).setText(DataGenerator.mTabTitle[]));
mTabLayout.addTab(mTabLayout.newTab().setIcon(getResources().getDrawable(R.drawable.tab_attention_selector)).setText(DataGenerator.mTabTitle[]));
mTabLayout.addTab(mTabLayout.newTab().setIcon(getResources().getDrawable(R.drawable.tab_profile_selector)).setText(DataGenerator.mTabTitle[]));
}
private void onTabItemSelected(int position){
Fragment fragment = null;
switch (position){
case :
fragment = mFragmensts[];
break;
case :
fragment = mFragmensts[];
break;
case :
fragment = mFragmensts[];
break;
case :
fragment = mFragmensts[];
break;
}
if(fragment!=null) {
getSupportFragmentManager().beginTransaction().replace(R.id.home_container,fragment).commit();
}
}
}
Activity的代碼如上,很簡單,就是一個TabLayout,添加監聽器,然後向TabLayout中添加4個Tab,在addOnTabSelectedListener 中切換各個Tab對應的Fragment 。其中用到的一些資料放在了一個單獨的類中, DataGenerator,代碼如下:
public class DataGenerator {
public static final int []mTabRes = new int[]{R.drawable.tab_home_selector,R.drawable.tab_discovery_selector,R.drawable.tab_attention_selector,R.drawable.tab_profile_selector};
public static final int []mTabResPressed = new int[]{R.drawable.ic_tab_strip_icon_feed_selected,R.drawable.ic_tab_strip_icon_category_selected,R.drawable.ic_tab_strip_icon_pgc_selected,R.drawable.ic_tab_strip_icon_profile_selected};
public static final String []mTabTitle = new String[]{"首頁","發現","關注","我的"};
public static Fragment[] getFragments(String from){
Fragment fragments[] = new Fragment[];
fragments[] = HomeFragment.newInstance(from);
fragments[] = DiscoveryFragment.newInstance(from);
fragments[] = AttentionFragment.newInstance(from);
fragments[] = ProfileFragment.newInstance(from);
return fragments;
}
/**
* 擷取Tab 顯示的内容
* @param context
* @param position
* @return
*/
public static View getTabView(Context context,int position){
View view = LayoutInflater.from(context).inflate(R.layout.home_tab_content,null);
ImageView tabIcon = (ImageView) view.findViewById(R.id.tab_content_image);
tabIcon.setImageResource(DataGenerator.mTabRes[position]);
TextView tabText = (TextView) view.findViewById(R.id.tab_content_text);
tabText.setText(mTabTitle[position]);
return view;
}
}
運作之後,效果如上圖,What ? 圖示這麼小?圖示和文字之間的間距這麼寬?這當然不是我們想要的,試着用TabLayout的屬性調整呢?TabLayout 提供了設定Tab 圖示、tab 文字顔色,選中顔色,文字大小的屬性,但是很遺憾,圖示Icon和圖示與文字之間的間距是沒辦法調整的。
那麼就沒有辦法了嗎?在仔細查了一下TabLayout的API 後,找到了一個方法,Tab 中有一個setCustomView(View view)方法,也就是我們不用正常的方式建立Tab,我們可以提供一個自己定義的View 來建立Tab,這不就行了嘛,既然可以自定義,那麼icon的大小,icon和文字之間的間距,我們想怎樣就怎樣拉。于是我們自定義一個布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/tab_content_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
/>
<TextView
android:id="@+id/tab_content_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="10sp"
android:textColor="@android:color/darker_gray"
/>
</LinearLayout>
添加tab 的時候,用這個自定義的布局,改造後的Activity中的代碼如下這樣:
public class BottomTabLayoutActivity extends AppCompatActivity {
private TabLayout mTabLayout;
private Fragment []mFragmensts;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bottom_tab_layout_ac);
mFragmensts = DataGenerator.getFragments("TabLayout Tab");
initView();
}
private void initView() {
mTabLayout = (TabLayout) findViewById(R.id.bottom_tab_layout);
mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
onTabItemSelected(tab.getPosition());
// Tab 選中之後,改變各個Tab的狀态
for (int i=;i<mTabLayout.getTabCount();i++){
View view = mTabLayout.getTabAt(i).getCustomView();
ImageView icon = (ImageView) view.findViewById(R.id.tab_content_image);
TextView text = (TextView) view.findViewById(R.id.tab_content_text);
if(i == tab.getPosition()){ // 選中狀态
icon.setImageResource(DataGenerator.mTabResPressed[i]);
text.setTextColor(getResources().getColor(android.R.color.black));
}else{// 未選中狀态
icon.setImageResource(DataGenerator.mTabRes[i]);
text.setTextColor(getResources().getColor(android.R.color.darker_gray));
}
}
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
// 提供自定義的布局添加Tab
for(int i=;i<;i++){
mTabLayout.addTab(mTabLayout.newTab().setCustomView(DataGenerator.getTabView(this,i)));
}
}
private void onTabItemSelected(int position){
Fragment fragment = null;
switch (position){
case :
fragment = mFragmensts[];
break;
case :
fragment = mFragmensts[];
break;
case :
fragment = mFragmensts[];
break;
case :
fragment = mFragmensts[];
break;
}
if(fragment!=null) {
getSupportFragmentManager().beginTransaction().replace(R.id.home_container,fragment).commit();
}
}
}
總結:TayoutLayout 實作底部導航欄較為簡單,隻需幾步就能實作,能配合Viewpager使用。但是,就像上文說的,不能設定Icon大小和調整Icon和文字之間的間距。但是可以通過設定自定義布局的方式來實作我們想要的效果。需要我們自己來改變Tab切換的狀态。還有一點需要注意:設定OnTabChangeListener 需要在添加Tab之前,不然第一次不會回調onTabSelected()方法
demohttp://download.csdn.net/detail/qq_35549248/9920237