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

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

page_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 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、界面不可滑动,比较死板。

 

相关文章