關于底部菜單是什么,我想沒必要介紹了,在市場上的APP里太常見了,這里提供兩種方式來實現。
記得之前寫過幾篇關于底部菜單實現的方法,有興趣的朋友可以看看:
1、《安卓開發復習筆記——TabHost組件(一)(實現底部菜單導航)》
2、《安卓開發復習筆記——TabHost組件(二)(實現底部菜單導航)》
3、《安卓開發筆記——Fragment+FragmentTabHost組件(實現新浪微博底部菜單)》
今天帶來種相對更通俗易懂的寫法,不再和過去一樣去沿用TabHost了,這次我們直接用LinearLayout布局來實現,先來看下實現效果圖:
中間內容區域有兩種實現方式:
1、ViewPager --可滑動界面 2、Fragment --固定界面
1、界面分析

這里有個小技巧,把底部菜單欄的每一個小的LinearLayout的寬度都設置成0dp,然后用weight權重去分配它,中間內容區域也是把高度設置成0dp,然后用weight權重去分配它。(weight默認是把界面里空閑的位置作為劃分位置,所以這里的寬度或者高度要注意設置成0dp)
2、具體實現(內容區域為ViewPager可滑動界面)
布局文件:
activity_top.xml(頂部布局)

1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="55dp" 5 android:background="@drawable/title_bar"> 6 7 <TextView 8 android:layout_width="wrap_content" 9 android:layout_height="wrap_content"10 android:layout_centerInParent="true"11 android:text="微信"12 android:textSize="20dp" 13 android:textColor="#ffffff"/>14 15 </RelativeLayout>View Code
activity_bottom.xml(底部布局)

1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="wrap_content" 5 android:background="@drawable/bottom_bar" > 6 7 <LinearLayout 8 android:id="@+id/ll_home" 9 android:layout_width="0dp" 10 android:layout_height="wrap_content" 11 android:layout_weight="1" 12 android:gravity="center" 13 android:orientation="vertical" > 14 15 <ImageView 16 android:id="@+id/iv_home" 17 android:layout_width="wrap_content" 18 android:layout_height="wrap_content" 19 android:src="@drawable/tab_weixin_View Codeactivity_main.xml(主布局,引入上下布局)
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 7 <include layout="@layout/activity_top" /> 8 9 <android.support.v4.view.ViewPager10 android:id="@+id/vp_content"11 android:layout_width="match_parent"12 android:background="#ffffff"13 android:layout_height="0dp"14 android:layout_weight="1" >15 </android.support.v4.view.ViewPager>16 17 <include layout="@layout/activity_bottom" />18 19 </LinearLayout>View Codepage_01.xml-page_04.xml(4個ViewPager的滑動界面,由于內容簡單這里只給出其中1個)
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent"> 5 6 <TextView 7 android:layout_width="wrap_content" 8 android:layout_height="wrap_content" 9 android:layout_centerInParent="true"10 android:text="我是微信首頁"11 android:textSize="30dp" />12 13 </RelativeLayout>View Code具體實現代碼:
ViewPager適配器(關于ViewPager的使用方法這里就不多說了,不清楚的朋友看我這篇文章吧《安卓開發筆記——ViewPager組件(仿微信引導界面)》)
1 package com.rabbit.tabdemo; 2 3 import java.util.List; 4 5 import android.support.v4.view.PagerAdapter; 6 import android.view.View; 7 import android.view.ViewGroup; 8 /** 9 * ViewPager適配器10 * @author Balla_兔子11 *12 */13 public class ContentAdapter extends PagerAdapter {14 15 private List<View> views;16 17 public ContentAdapter(List<View> views) {18 this.views = views;19 }20 21 @Override22 public int getCount() {23 return views.size();24 }25 26 @Override27 public boolean isViewFromObject(View arg0, Object arg1) {28 return arg0 == arg1;29 }30 31 @Override32 public Object instantiateItem(ViewGroup container, int position) {33 View view = views.get(position);34 container.addView(view);35 return view;36 }37 38 @Override39 public void destroyItem(ViewGroup container, int position, Object object) {40 container.removeView(views.get(position));41 }42 43 }MainActivity(主界面代碼)
初始化控件后,完成對底部菜單的4個LinearLayout的點擊監聽事件,在用戶觸發點擊事件的時候,設置選擇狀態然后跳轉相對應的界面。為了使得滑動ViewPager也能同時觸發底部菜單狀態的改變,這里也對ViewPager設置了滑動監聽。其他的代碼注釋很全,看注釋就可以了。
1 package com.rabbit.tabdemo; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import android.app.Activity; 7 import android.os.Bundle; 8 import android.support.v4.view.ViewPager; 9 import android.support.v4.view.ViewPager.OnPageChangeListener; 10 import android.view.View; 11 import android.view.View.OnClickListener; 12 import android.widget.ImageView; 13 import android.widget.LinearLayout; 14 import android.widget.TextView; 15 16 public class MainActivity extends Activity implements OnClickListener,OnPageChangeListener{ 17 18 // 底部菜單4個Linearlayout 19 private LinearLayout ll_home; 20 private LinearLayout ll_address; 21 private LinearLayout ll_friend; 22 private LinearLayout ll_setting; 23 24 // 底部菜單4個ImageView 25 private ImageView iv_home; 26 private ImageView iv_address; 27 private ImageView iv_friend; 28 private ImageView iv_setting; 29 30 // 底部菜單4個菜單標題 31 private TextView tv_home; 32 private TextView tv_address; 33 private TextView tv_friend; 34 private TextView tv_setting; 35 36 // 中間內容區域 37 private ViewPager viewPager; 38 39 // ViewPager適配器ContentAdapter 40 private ContentAdapter adapter; 41 42 private List<View> views; 43 44 @Override 45 protected void onCreate(Bundle savedInstanceState) { 46 super.onCreate(savedInstanceState); 47 setContentView(R.layout.activity_main); 48 49 // 初始化控件 50 initView(); 51 // 初始化底部按鈕事件 52 initEvent(); 53 54 } 55 56 private void initEvent() { 57 // 設置按鈕監聽 58 ll_home.setOnClickListener(this); 59 ll_address.setOnClickListener(this); 60 ll_friend.setOnClickListener(this); 61 ll_setting.setOnClickListener(this); 62 63 //設置ViewPager滑動監聽 64 viewPager.setOnPageChangeListener(this); 65 } 66 67 private void initView() { 68 69 // 底部菜單4個Linearlayout 70 this.ll_home = (LinearLayout) findViewById(R.id.ll_home); 71 this.ll_address = (LinearLayout) findViewById(R.id.ll_address); 72 this.ll_friend = (LinearLayout) findViewById(R.id.ll_friend); 73 this.ll_setting = (LinearLayout) findViewById(R.id.ll_setting); 74 75 // 底部菜單4個ImageView 76 this.iv_home = (ImageView) findViewById(R.id.iv_home); 77 this.iv_address = (ImageView) findViewById(R.id.iv_address); 78 this.iv_friend = (ImageView) findViewById(R.id.iv_friend); 79 this.iv_setting = (ImageView) findViewById(R.id.iv_setting); 80 81 // 底部菜單4個菜單標題 82 this.tv_home = (TextView) findViewById(R.id.tv_home); 83 this.tv_address = (TextView) findViewById(R.id.tv_address); 84 this.tv_friend = (TextView) findViewById(R.id.tv_friend); 85 this.tv_setting = (TextView) findViewById(R.id.tv_setting); 86 87 // 中間內容區域ViewPager 88 this.viewPager = (ViewPager) findViewById(R.id.vp_content); 89 90 // 適配器 91 View page_01 = View.inflate(MainActivity.this, R.layout.page_01, null); 92 View page_02 = View.inflate(MainActivity.this, R.layout.page_02, null); 93 View page_03 = View.inflate(MainActivity.this, R.layout.page_03, null); 94 View page_04 = View.inflate(MainActivity.this, R.layout.page_04, null); 95 96 views = new ArrayList<View>(); 97 views.add(page_01); 98 views.add(page_02); 99 views.add(page_03);100 views.add(page_04);101 102 this.adapter = new ContentAdapter(views);103 viewPager.setAdapter(adapter);104 105 }106 107 @Override108 public void onClick(View v) {109 // 在每次點擊后將所有的底部按鈕(ImageView,TextView)顏色改為灰色,然后根據點擊著色110 restartBotton();111 // ImageView和TetxView置為綠色,頁面隨之跳轉112 switch (v.getId()) {113 case R.id.ll_home:114 iv_home.setImageResource(R.drawable.tab_weixin_pressed);115 tv_home.setTextColor(0xff1B940A);116 viewPager.setCurrentItem(0);117 break;118 case R.id.ll_address:119 iv_address.setImageResource(R.drawable.tab_address_pressed);120 tv_address.setTextColor(0xff1B940A);121 viewPager.setCurrentItem(1);122 break;123 case R.id.ll_friend:124 iv_friend.setImageResource(R.drawable.tab_find_frd_pressed);125 tv_friend.setTextColor(0xff1B940A);126 viewPager.setCurrentItem(2);127 break;128 case R.id.ll_setting:129 iv_setting.setImageResource(R.drawable.tab_find_frd_pressed);130 tv_setting.setTextColor(0xff1B940A);131 viewPager.setCurrentItem(3);132 break;133 134 default:135 break;136 }137 138 }139 140 private void restartBotton() {141 // ImageView置為灰色142 iv_home.setImageResource(R.drawable.tab_weixin_normal);143 iv_address.setImageResource(R.drawable.tab_address_normal);144 iv_friend.setImageResource(R.drawable.tab_find_frd_normal);145 iv_setting.setImageResource(R.drawable.tab_settings_normal);146 // TextView置為白色147 tv_home.setTextColor(0xffffffff);148 tv_address.setTextColor(0xffffffff);149 tv_friend.setTextColor(0xffffffff);150 tv_setting.setTextColor(0xffffffff);151 }152 153 @Override154 public void onPageScrollStateChanged(int arg0) {155 156 }157 158 @Override159 public void onPageScrolled(int arg0, float arg1, int arg2) {160 161 }162 163 @Override164 public void onPageSelected(int arg0) {165 restartBotton();166 //當前view被選擇的時候,改變底部菜單圖片,文字顏色167 switch (arg0) {168 case 0:169 iv_home.setImageResource(R.drawable.tab_weixin_pressed);170 tv_home.setTextColor(0xff1B940A);171 break;172 case 1:173 iv_address.setImageResource(R.drawable.tab_address_pressed);174 tv_address.setTextColor(0xff1B940A);175 break;176 case 2:177 iv_friend.setImageResource(R.drawable.tab_find_frd_pressed);178 tv_friend.setTextColor(0xff1B940A);179 break;180 case 3:181 iv_setting.setImageResource(R.drawable.tab_find_frd_pressed);182 tv_setting.setTextColor(0xff1B940A);183 break;184 185 default:186 break;187 }188 189 }190 191 }3、具體實現(內容區域為Fragment固定界面)
布局文件:
布局文件基本沒變化,只是把主界面的ViewPager改成了FramLayout,其他文件保持一致,就不貼出來了。
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 7 <include layout="@layout/activity_top" /> 8 9 <FrameLayout10 android:id="@+id/fl_content"11 android:layout_width="match_parent"12 android:background="#ffffff"13 android:layout_height="0dp"14 android:layout_weight="1" >15 </FrameLayout>16 17 <include layout="@layout/activity_bottom" />18 19 </LinearLayout>View Code具體實現代碼:
由于這次的內容是基于Fragment的,所以需要有4個Fragment文件,由于代碼相同這里只貼出一個。
Frgament(HomeFragment,AddressFragment,FriendFragment,SettingFragment)
1 package com.rabbit.tabdemo; 2 3 import android.os.Bundle; 4 import android.support.annotation.Nullable; 5 import android.support.v4.app.Fragment; 6 import android.view.LayoutInflater; 7 import android.view.View; 8 import android.view.ViewGroup; 9 10 public class HomeFragment extends Fragment {11 @Override12 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {13 return inflater.inflate(R.layout.page_01, container, false);14 }15 16 }View CodeMainActivity(主界面代碼)
代碼很簡單,一看就能明白就不多說什么了,只提個需要注意的地方,由于便于向下兼容這里的Fragment是用V4包下的,在導入包的時候需要注意一下。
1 package com.rabbit.tabdemo; 2 3 import android.os.Bundle; 4 import android.support.v4.app.Fragment; 5 import android.support.v4.app.FragmentActivity; 6 import android.support.v4.app.FragmentManager; 7 import android.support.v4.app.FragmentTransaction; 8 import android.view.View; 9 import android.view.View.OnClickListener; 10 import android.widget.ImageView; 11 import android.widget.LinearLayout; 12 import android.widget.TextView; 13 14 public class MainActivity extends FragmentActivity implements OnClickListener { 15 // 底部菜單4個Linearlayout 16 private LinearLayout ll_home; 17 private LinearLayout ll_address; 18 private LinearLayout ll_friend; 19 private LinearLayout ll_setting; 20 21 // 底部菜單4個ImageView 22 private ImageView iv_home; 23 private ImageView iv_address; 24 private ImageView iv_friend; 25 private ImageView iv_setting; 26 27 // 底部菜單4個菜單標題 28 private TextView tv_home; 29 private TextView tv_address; 30 private TextView tv_friend; 31 private TextView tv_setting; 32 33 // 4個Fragment 34 private Fragment homeFragment; 35 private Fragment addressFragment; 36 private Fragment friendFragment; 37 private Fragment settingFragment; 38 39 @Override 40 protected void onCreate(Bundle savedInstanceState) { 41 super.onCreate(savedInstanceState); 42 setContentView(R.layout.activity_main); 43 44 // 初始化控件 45 initView(); 46 // 初始化底部按鈕事件 47 initEvent(); 48 // 初始化并設置當前Fragment 49 initFragment(0); 50 51 } 52 53 private void initFragment(int index) { 54 // 由于是引用了V4包下的Fragment,所以這里的管理器要用getSupportFragmentManager獲取 55 FragmentManager fragmentManager = getSupportFragmentManager(); 56 // 開啟事務 57 FragmentTransaction transaction = fragmentManager.beginTransaction(); 58 // 隱藏所有Fragment 59 hideFragment(transaction); 60 switch (index) { 61 case 0: 62 if (homeFragment == null) { 63 homeFragment = new HomeFragment(); 64 transaction.add(R.id.fl_content, homeFragment); 65 } else { 66 transaction.show(homeFragment); 67 } 68 break; 69 case 1: 70 if (addressFragment == null) { 71 addressFragment = new AddressFragment(); 72 transaction.add(R.id.fl_content, addressFragment); 73 } else { 74 transaction.show(addressFragment); 75 } 76 77 break; 78 case 2: 79 if (friendFragment == null) { 80 friendFragment = new FriendFragment(); 81 transaction.add(R.id.fl_content, friendFragment); 82 } else { 83 transaction.show(friendFragment); 84 } 85 86 break; 87 case 3: 88 if (settingFragment == null) { 89 settingFragment = new SettingFragment(); 90 transaction.add(R.id.fl_content, settingFragment); 91 } else { 92 transaction.show(settingFragment); 93 } 94 95 break; 96 97 default: 98 break; 99 }100 101 // 提交事務102 transaction.commit();103 104 }105 106 //隱藏Fragment107 private void hideFragment(FragmentTransaction transaction) {108 if (homeFragment != null) {109 transaction.hide(homeFragment);110 }111 if (addressFragment != null) {112 transaction.hide(addressFragment);113 }114 if (friendFragment != null) {115 transaction.hide(friendFragment);116 }117 if (settingFragment != null) {118 transaction.hide(settingFragment);119 }120 121 }122 123 private void initEvent() {124 // 設置按鈕監聽125 ll_home.setOnClickListener(this);126 ll_address.setOnClickListener(this);127 ll_friend.setOnClickListener(this);128 ll_setting.setOnClickListener(this);129 130 }131 132 private void initView() {133 134 // 底部菜單4個Linearlayout135 this.ll_home = (LinearLayout) findViewById(R.id.ll_home);136 this.ll_address = (LinearLayout) findViewById(R.id.ll_address);137 this.ll_friend = (LinearLayout) findViewById(R.id.ll_friend);138 this.ll_setting = (LinearLayout) findViewById(R.id.ll_setting);139 140 // 底部菜單4個ImageView141 this.iv_home = (ImageView) findViewById(R.id.iv_home);142 this.iv_address = (ImageView) findViewById(R.id.iv_address);143 this.iv_friend = (ImageView) findViewById(R.id.iv_friend);144 this.iv_setting = (ImageView) findViewById(R.id.iv_setting);145 146 // 底部菜單4個菜單標題147 this.tv_home = (TextView) findViewById(R.id.tv_home);148 this.tv_address = (TextView) findViewById(R.id.tv_address);149 this.tv_friend = (TextView) findViewById(R.id.tv_friend);150 this.tv_setting = (TextView) findViewById(R.id.tv_setting);151 152 }153 154 @Override155 public void onClick(View v) {156 157 // 在每次點擊后將所有的底部按鈕(ImageView,TextView)顏色改為灰色,然后根據點擊著色158 restartBotton();159 // ImageView和TetxView置為綠色,頁面隨之跳轉160 switch (v.getId()) {161 case R.id.ll_home:162 iv_home.setImageResource(R.drawable.tab_weixin_pressed);163 tv_home.setTextColor(0xff1B940A);164 initFragment(0);165 break;166 case R.id.ll_address:167 iv_address.setImageResource(R.drawable.tab_address_pressed);168 tv_address.setTextColor(0xff1B940A);169 initFragment(1);170 break;171 case R.id.ll_friend:172 iv_friend.setImageResource(R.drawable.tab_find_frd_pressed);173 tv_friend.setTextColor(0xff1B940A);174 initFragment(2);175 break;176 case R.id.ll_setting:177 iv_setting.setImageResource(R.drawable.tab_find_frd_pressed);178 tv_setting.setTextColor(0xff1B940A);179 initFragment(3);180 break;181 182 default:183 break;184 }185 186 }187 188 private void restartBotton() {189 // ImageView置為灰色190 iv_home.setImageResource(R.drawable.tab_weixin_normal);191 iv_address.setImageResource(R.drawable.tab_address_normal);192 iv_friend.setImageResource(R.drawable.tab_find_frd_normal);193 iv_setting.setImageResource(R.drawable.tab_settings_normal);194 // TextView置為白色195 tv_home.setTextColor(0xffffffff);196 tv_address.setTextColor(0xffffffff);197 tv_friend.setTextColor(0xffffffff);198 tv_setting.setTextColor(0xffffffff);199 }200 201 }
![]()
到這里界面效果就基本實現了,就算是旋轉屏幕也能夠很好的達到適配效果,最后我們還需要做的2點,可能有些朋友已經發現了,在我們旋轉屏幕的時候,Fragment會重新調用onCreate方法,導致成員變量重新初始化了一次,Fragment對象也重置為空,然后就調用不到hide方法,從而出現了界面重復疊加的情況。
下面提供解決的方法,其實很簡單,只需要在AndroidManifest.xml里面對應的activity里添設置改換屏幕方向等操作時不觸發oncreate事件就可以。
1 android:configChanges="orientation|keyboardHidden|screenSize"最后我們隱藏下標題欄,在application里添加上:
1 android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"這樣就大功告成了!
總結:
基于ViewPager實現的內容:
優點:
1、界面可以滑動,美觀,流暢。
缺點:
1、當界面里有一些需要用手勢來實現的內容會起沖突,比如我們ListView里的側滑刪除。
2、由于采用的是ViewPager,所以頁面內容實現代碼會嚴重依賴于MainActivity,代碼太過冗余,不便于后期維護。
基于Fragment實現的內容:
優點:
1、Fragment文件單獨存在,各自頁面的內容各自去實現完成,有自己的生命周期,便于后期維護。
2、對于需要手勢操作的一些內容不會起沖突。
缺點:
1、界面不可滑動,比較死板。
補充:如果既想有ViewPager的滑動效果,又想ViewPager的頁卡里嵌套Fragment,可以使用FragmentPagerAdapter作為適配器,但需要注意Fragment生命周期的管理。
作者:Balla_兔子出處:http://m.survivalescaperooms.com/lichenwei/本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。正在看本人博客的這位童鞋,我看你氣度不凡,談吐間隱隱有王者之氣,日后必有一番作為!旁邊有“推薦”二字,你就順手把它點了吧,相得準,我分文不收;相不準,你也好回來找我!
新聞熱點
疑難解答