你的位置:首页 > Java教程

[Java教程]安卓开发笔记——多种方式实现底部菜单栏(仿微信界面)


关于底部菜单是什么,我想没必要介绍了,在市场上的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.

 1 <RelativeLayout ="http://schemas.android.com/apk/res/android" 2   ="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.

 1 <LinearLayout ="http://schemas.android.com/apk/res/android" 2   ="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_pressed" /> 20  21     <TextView 22       android:id="@+id/tv_home" 23       android:layout_width="wrap_content" 24       android:layout_height="wrap_content" 25       android:layout_marginTop="3dp" 26       android:text="首页" 27       android:textColor="#1B940A" 28       android:textStyle="bold" /> 29   </LinearLayout> 30  31   <LinearLayout 32     android:id="@+id/ll_address" 33     android:layout_width="0dp" 34     android:layout_height="wrap_content" 35     android:layout_weight="1" 36     android:gravity="center" 37     android:orientation="vertical" > 38  39     <ImageView 40       android:id="@+id/iv_address" 41       android:layout_width="wrap_content" 42       android:layout_height="wrap_content" 43       android:src="@drawable/tab_address_normal" /> 44  45     <TextView 46       android:id="@+id/tv_address" 47       android:layout_width="wrap_content" 48       android:layout_height="wrap_content" 49       android:layout_marginTop="3dp" 50       android:text="通讯录" 51       android:textColor="#ffffff" 52       android:textStyle="bold" /> 53   </LinearLayout> 54  55   <LinearLayout 56     android:id="@+id/ll_friend" 57     android:layout_width="0dp" 58     android:layout_height="wrap_content" 59     android:layout_weight="1" 60     android:gravity="center" 61     android:orientation="vertical" > 62  63     <ImageView 64       android:id="@+id/iv_friend" 65       android:layout_width="wrap_content" 66       android:layout_height="wrap_content" 67       android:src="@drawable/tab_find_frd_normal" /> 68  69     <TextView 70       android:id="@+id/tv_friend" 71       android:layout_width="wrap_content" 72       android:layout_height="wrap_content" 73       android:layout_marginTop="3dp" 74       android:text="朋友" 75       android:textColor="#ffffff" 76       android:textStyle="bold" /> 77   </LinearLayout> 78  79   <LinearLayout 80     android:id="@+id/ll_setting" 81     android:layout_width="0dp" 82     android:layout_height="wrap_content" 83     android:layout_weight="1" 84     android:gravity="center" 85     android:orientation="vertical" > 86  87     <ImageView 88       android:id="@+id/iv_setting" 89       android:layout_width="wrap_content" 90       android:layout_height="wrap_content" 91       android:src="@drawable/tab_settings_normal" /> 92  93     <TextView 94       android:id="@+id/tv_setting" 95       android:layout_width="wrap_content" 96       android:layout_height="wrap_content" 97       android:layout_marginTop="3dp" 98       android:text="设置" 99       android:textColor="#ffffff"100       android:textStyle="bold" />101   </LinearLayout>102 103 </LinearLayout>

View Code

activity_main.

 1 <LinearLayout ="http://schemas.android.com/apk/res/android" 2   ="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 Code

page_01.

 1 <RelativeLayout ="http://schemas.android.com/apk/res/android" 2   ="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 ="http://schemas.android.com/apk/res/android" 2   ="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 Code

 

MainActivity(主界面代码)

代码很简单,一看就能明白就不多说什么了,只提个需要注意的地方,由于便于向下兼容这里的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 }

 

总结:

基于ViewPager实现的内容:

优点:

1、界面可以滑动,美观,流畅。

缺点:

1、当界面里有一些需要用手势来实现的内容会起冲突,比如我们ListView里的侧滑删除。

2、由于采用的是ViewPager,所以页面内容实现代码会严重依赖于MainActivity,代码太过冗余,不便于后期维护。

 

基于Fragment实现的内容:

优点:

1、Fragment文件单独存在,各自页面的内容各自去实现完成,有自己的生命周期,便于后期维护。

2、对于需要手势操作的一些内容不会起冲突。

缺点:

1、界面不可滑动,比较死板。