安卓开发笔记——多种方式实现底部菜单栏(仿微信界面)
关于底部菜单是什么,我想没必要介绍了,在市场上的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_height10 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 2 3 4 5 ="@drawable/bottom_bar" 6 7 LinearLayout 8 android:id="@+id/ll_home" 9 android:layout_width="0dp" 10 11 android:layout_weight="1" 12 android:gravity="center" 13 android:orientation="vertical" 14 15 ImageView 16 ="@+id/iv_home" 17 android:layout_width 18 android:layout_height 19 android:src="@drawable/tab_weixin_pressed" 20 21 22 ="@+id/tv_home" 23 24 25 android:layout_marginTop="3dp" 26 android:text="首页" 27 android:textColor="#1B940A" 28 android:textStyle="bold" 29 LinearLayout 30 31 32 ="@+id/ll_address" 33 34 35 36 37 38 39 40 ="@+id/iv_address" 41 42 43 ="@drawable/tab_address_normal" 44 45 46 ="@+id/tv_address" 47 48 49 50 ="通讯录" 51 ="#ffffff" 52 53 54 55 56 ="@+id/ll_friend" 57 58 59 60 61 62 63 64 ="@+id/iv_friend" 65 66 67 ="@drawable/tab_find_frd_normal" 68 69 70 ="@+id/tv_friend" 71 72 73 74 ="朋友" 75 76 77 78 79 80 ="@+id/ll_setting" 81 82 83 84 85 86 87 88 ="@+id/iv_setting" 89 90 91 ="@drawable/tab_settings_normal" 92 93 94 ="@+id/tv_setting" 95 96 97 98 ="设置" 99 100 101 102 103 >View Code activity_main.xml(主布局,引入上下布局) android:orientationinclude layout="@layout/activity_top" 8 9 android.support.v4.view.ViewPager 10 ="@+id/vp_content" android:background14 ="1" 15 android.support.v4.view.ViewPager16 17 ="@layout/activity_bottom" 18 19 >View Code page_01.xml-page_04.xml(4个ViewPager的滑动界面,由于内容简单这里只给出其中1个) ="match_parent" 5 6 7 8 ="我是微信首页" ="30dp" 12 13 >View Code ? 具体实现代码: ViewPager适配器(关于ViewPager的使用方法这里就不多说了,不清楚的朋友看我这篇文章吧《安卓开发笔记——ViewPager组件(仿微信引导界面)》) package com.rabbit.tabdemo; 2 3 import java.util.List; 4 5 android.support.v4.view.PagerAdapter; 6 android.view.View; 7 android.view.ViewGroup; 8 /** 9 * ViewPager适配器 10 * @author Balla_兔子 11 * 12 */ public class ContentAdapter extends PagerAdapter { private List<View> views; public ContentAdapter(List<View> views) { 18 this.views = } 20 21 @Override 22 int getCount() { 23 return views.size(); 24 25 26 27 boolean isViewFromObject(View arg0,Object arg1) { 28 return arg0 == arg1; 29 30 31 32 public Object instantiateItem(ViewGroup container, position) { 33 View view = views.get(position); 34 container.addView(view); 35 view; 36 37 38 39 void destroyItem(ViewGroup container,1)"> position,Object object) { 40 container.removeView(views.get(position)); 41 42 43 } ? MainActivity(主界面代码) 初始化控件后,完成对底部菜单的4个LinearLayout的点击监听事件,在用户触发点击事件的时候,设置选择状态然后跳转相对应的界面。为了使得滑动ViewPager也能同时触发底部菜单状态的改变,这里也对ViewPager设置了滑动监听。其他的代码注释很全,看注释就可以了。 2 3 java.util.ArrayList; 4 5 6 android.app.Activity; 7 android.os.Bundle; 8 android.support.v4.view.ViewPager; 9 android.support.v4.view.ViewPager.OnPageChangeListener; 10 11 android.view.View.OnClickListener; 12 android.widget.ImageView; 13 android.widget.LinearLayout; 14 android.widget.TextView; 15 16 class MainActivity extends Activity implements OnClickListener,OnPageChangeListener{ 17 18 // 底部菜单4个Linearlayout 19 private LinearLayout ll_home; 20 LinearLayout ll_address; 21 LinearLayout ll_friend; 22 LinearLayout ll_setting; 23 24 底部菜单4个ImageView 25 ImageView iv_home; 26 ImageView iv_address; 27 ImageView iv_friend; 28 ImageView iv_setting; 29 30 底部菜单4个菜单标题 TextView tv_home; 32 TextView tv_address; 33 TextView tv_friend; 34 TextView tv_setting; 35 36 中间内容区域 37 ViewPager viewPager; 39 ViewPager适配器ContentAdapter 40 ContentAdapter adapter; 41 42 43 44 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 initEvent() { 57 设置按钮监听 58 ll_home.setOnClickListener(this); 59 ll_address.setOnClickListener( 60 ll_friend.setOnClickListener( 61 ll_setting.setOnClickListener( 62 设置ViewPager滑动监听 64 viewPager.setOnPageChangeListener( 65 66 67 initView() { 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 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 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); 中间内容区域ViewPager 88 this.viewPager = (ViewPager) findViewById(R.id.vp_content); 89 90 适配器 91 View page_01 = View.inflate(MainActivity.this,R.layout.page_01,1)">null 92 View page_02 = View.inflate(MainActivity. 93 View page_03 = View.inflate(MainActivity. 94 View page_04 = View.inflate(MainActivity. 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); viewPager.setAdapter(adapter); 104 105 106 107 108 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(0xff1B940A116 viewPager.setCurrentItem(0117 break; 118 R.id.ll_address: 119 iv_address.setImageResource(R.drawable.tab_address_pressed); 120 tv_address.setTextColor(0xff1B940A121 viewPager.setCurrentItem(1122 123 R.id.ll_friend: 124 iv_friend.setImageResource(R.drawable.tab_find_frd_pressed); 125 tv_friend.setTextColor(0xff1B940A126 viewPager.setCurrentItem(2127 128 R.id.ll_setting: 129 iv_setting.setImageResource(R.drawable.tab_find_frd_pressed); 130 tv_setting.setTextColor(0xff1B940A131 viewPager.setCurrentItem(3132 133 134 default: 135 136 } 137 138 139 140 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(0xffffffff148 tv_address.setTextColor(0xffffffff149 tv_friend.setTextColor(0xffffffff150 tv_setting.setTextColor(0xffffffff151 152 153 154 void onPageScrollStateChanged( arg0) { 155 156 157 158 159 void onPageScrolled(int arg0,1)">float arg1,1)"> arg2) { 160 161 162 163 164 void onPageSelected(165 166 当前view被选择的时候,改变底部菜单图片,文字颜色 167 (arg0) { 168 case 0169 170 tv_home.setTextColor(0xff1B940A171 172 case 1173 174 tv_address.setTextColor(0xff1B940A175 176 case 2177 178 tv_friend.setTextColor(0xff1B940A179 180 case 3181 182 tv_setting.setTextColor(0xff1B940A183 184 185 186 187 188 189 190 191 } ? 3、具体实现(内容区域为Fragment固定界面) 布局文件: 布局文件基本没变化,只是把主界面的ViewPager改成了FramLayout,其他文件保持一致,就不贴出来了。 FrameLayout ="@+id/fl_content" FrameLayout>View Code ? 具体实现代码: 由于这次的内容是基于Fragment的,所以需要有4个Fragment文件,由于代码相同这里只贴出一个。 Frgament(HomeFragment,AddressFragment,FriendFragment,SettingFragment) @H_302_1404@ 4 android.support.annotation.Nullable; android.support.v4.app.Fragment; android.view.LayoutInflater; 9 class HomeFragment Fragment { 12 public View onCreateView(LayoutInflater inflater,@Nullable ViewGroup container,@Nullable Bundle savedInstanceState) { 13 return inflater.inflate(R.layout.page_01,container,1)">false14 15 16 }View Code ? MainActivity(主界面代码) 代码很简单,一看就能明白就不多说什么了,只提个需要注意的地方,由于便于向下兼容这里的Fragment是用V4包下的,在导入包的时候需要注意一下。 5 android.support.v4.app.FragmentActivity; android.support.v4.app.FragmentManager; android.support.v4.app.FragmentTransaction; 13 extends FragmentActivity OnClickListener { 15 16 17 23 26 32 4个Fragment Fragment homeFragment; 35 Fragment addressFragment; Fragment friendFragment; Fragment settingFragment; 39 41 42 44 45 48 初始化并设置当前Fragment 49 initFragment(0 50 51 52 void initFragment( index) { 54 由于是引用了V4包下的Fragment,所以这里的管理器要用getSupportFragmentManager获取 55 FragmentManager fragmentManager = getSupportFragmentManager(); 56 开启事务 57 FragmentTransaction transaction = fragmentManager.beginTransaction(); 58 隐藏所有Fragment 59 hideFragment(transaction); 60 (index) { 61 62 if (homeFragment == ) { 63 homeFragment = HomeFragment(); 64 transaction.add(R.id.fl_content,homeFragment); 65 } else { 66 transaction.show(homeFragment); 67 } 68 70 if (addressFragment == 71 addressFragment = AddressFragment(); 72 73 } 74 transaction.show(addressFragment); 75 76 77 79 if (friendFragment == 80 friendFragment = FriendFragment(); 81 82 } 83 transaction.show(friendFragment); 84 85 86 88 if (settingFragment == 89 settingFragment = SettingFragment(); 90 91 } 92 transaction.show(settingFragment); 93 94 95 96 97 98 100 101 提交事务 102 transaction.commit(); 103 104 105 106 隐藏Fragment 107 hideFragment(FragmentTransaction transaction) { 108 if (homeFragment != 109 transaction.hide(homeFragment); if (addressFragment != 112 transaction.hide(addressFragment); 113 114 if (friendFragment != 115 transaction.hide(friendFragment); 116 117 if (settingFragment != 118 transaction.hide(settingFragment); 120 121 122 123 124 125 ll_home.setOnClickListener(126 ll_address.setOnClickListener(127 ll_friend.setOnClickListener(128 ll_setting.setOnClickListener(129 130 131 132 135 136 137 138 140 142 143 144 145 147 148 149 150 151 152 153 154 155 156 157 159 160 161 162 163 tv_home.setTextColor(0xff1B940A164 initFragment(0165 167 168 tv_address.setTextColor(0xff1B940A169 initFragment(1170 171 172 173 tv_friend.setTextColor(0xff1B940A174 initFragment(2178 tv_setting.setTextColor(0xff1B940A179 initFragment(3180 181 182 184 185 186 187 188 189 190 191 192 193 194 195 tv_home.setTextColor(0xffffffff196 tv_address.setTextColor(0xffffffff197 tv_friend.setTextColor(0xffffffff198 tv_setting.setTextColor(0xffffffff199 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_兔子 ? (编辑:北几岛) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |