本文(争取做到)Android 最全的底部导航栏实现方法.

现在写了4个主要方法.

还有一些个人感觉不完全切题的方法也会简单介绍一下.

方法一. ViewPager + List<View> + PagerAdapter

先看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. <LinearLayout
  7. android:layout_width="match_parent"
  8. android:layout_height="45dp"
  9. android:background="#0E6DB0"
  10. android:gravity="center"
  11. android:orientation="vertical" >
  12. <TextView
  13. android:layout_width="wrap_content"
  14. android:layout_height="wrap_content"
  15. android:layout_gravity="center"
  16. android:text="@string/app_name"
  17. android:textColor="#ffffff"
  18. android:textSize="20sp"
  19. android:textStyle="bold" />
  20. </LinearLayout>
  21. <android.support.v4.view.ViewPager
  22. android:id="@+id/viewPager"
  23. android:layout_width="match_parent"
  24. android:layout_height="0dp"
  25. android:layout_weight="1" >
  26. </android.support.v4.view.ViewPager>
  27. <LinearLayout
  28. android:layout_width="match_parent"
  29. android:layout_height="55dp"
  30. android:background="#0E6DB0"
  31. android:orientation="horizontal" >
  32. <LinearLayout
  33. android:id="@+id/llChat"
  34. android:layout_width="0dp"
  35. android:layout_height="match_parent"
  36. android:layout_weight="1"
  37. android:gravity="center"
  38. android:orientation="vertical" >
  39. <ImageView
  40. android:id="@+id/ivChat"
  41. android:layout_width="wrap_content"
  42. android:layout_height="wrap_content"
  43. android:background="#00000000"
  44. android:src="@drawable/tab_chat" />
  45. <TextView
  46. android:id="@+id/tvChat"
  47. android:layout_width="wrap_content"
  48. android:layout_height="wrap_content"
  49. android:text="微信"
  50. android:textColor="@drawable/tab_textview" />
  51. </LinearLayout>
  52. <LinearLayout
  53. android:id="@+id/llFriends"
  54. android:layout_width="0dp"
  55. android:layout_height="match_parent"
  56. android:layout_weight="1"
  57. android:gravity="center"
  58. android:orientation="vertical" >
  59. <ImageView
  60. android:id="@+id/ivFriends"
  61. android:layout_width="wrap_content"
  62. android:layout_height="wrap_content"
  63. android:background="#00000000"
  64. android:src="@drawable/tab_friends" />
  65. <TextView
  66. android:id="@+id/tvFriends"
  67. android:layout_width="wrap_content"
  68. android:layout_height="wrap_content"
  69. android:text="朋友"
  70. android:textColor="@drawable/tab_textview" />
  71. </LinearLayout>
  72. <LinearLayout
  73. android:id="@+id/llContacts"
  74. android:layout_width="0dp"
  75. android:layout_height="match_parent"
  76. android:layout_weight="1"
  77. android:gravity="center"
  78. android:orientation="vertical" >
  79. <ImageView
  80. android:id="@+id/ivContacts"
  81. android:layout_width="wrap_content"
  82. android:layout_height="wrap_content"
  83. android:background="#00000000"
  84. android:src="@drawable/tab_contacts" />
  85. <TextView
  86. android:id="@+id/tvContacts"
  87. android:layout_width="wrap_content"
  88. android:layout_height="wrap_content"
  89. android:text="通讯录"
  90. android:textColor="@drawable/tab_textview" />
  91. </LinearLayout>
  92. <LinearLayout
  93. android:id="@+id/llSettings"
  94. android:layout_width="0dp"
  95. android:layout_height="match_parent"
  96. android:layout_weight="1"
  97. android:gravity="center"
  98. android:orientation="vertical" >
  99. <ImageView
  100. android:id="@+id/ivSettings"
  101. android:layout_width="wrap_content"
  102. android:layout_height="wrap_content"
  103. android:background="#00000000"
  104. android:src="@drawable/tab_setting" />
  105. <TextView
  106. android:id="@+id/tvSettings"
  107. android:layout_width="wrap_content"
  108. android:layout_height="wrap_content"
  109. android:text="设置"
  110. android:textColor="@drawable/tab_textview" />
  111. </LinearLayout>
  112. </LinearLayout>
  113. </LinearLayout>
 
说明一:还有另一种方式是用RadioGroup的方式,但是那种方式如果以后要包含小红点提醒或者右上角数字角标提醒,就不好灵活的修改了.所以本文忽略那种方法.
说明二:底部导航栏的4个ImageView使用的src, TextView使用的textColor都是seletor
 
 
然后看MainActivity.java
  1. package com.yao.tab01;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import android.app.Activity;
  5. import android.os.Bundle;
  6. import android.support.v4.view.ViewPager;
  7. import android.support.v4.view.ViewPager.OnPageChangeListener;
  8. import android.view.LayoutInflater;
  9. import android.view.View;
  10. import android.view.View.OnClickListener;
  11. import android.view.Window;
  12. import android.widget.ImageView;
  13. import android.widget.LinearLayout;
  14. import android.widget.TextView;
  15. public class MainActivity extends Activity implements OnClickListener {
  16. private List<View> views = new ArrayList<View>();
  17. private ViewPager viewPager;
  18. private LinearLayout llChat, llFriends, llContacts, llSettings;
  19. private ImageView ivChat, ivFriends, ivContacts, ivSettings, ivCurrent;
  20. private TextView tvChat, tvFriends, tvContacts, tvSettings, tvCurrent;
  21. @Override
  22. protected void onCreate(Bundle savedInstanceState) {
  23. super.onCreate(savedInstanceState);
  24. requestWindowFeature(Window.FEATURE_NO_TITLE);
  25. setContentView(R.layout.activity_main);
  26. initView();
  27. initData();
  28. }
  29. private void initView() {
  30. viewPager = (ViewPager) findViewById(R.id.viewPager);
  31. llChat = (LinearLayout) findViewById(R.id.llChat);
  32. llFriends = (LinearLayout) findViewById(R.id.llFriends);
  33. llContacts = (LinearLayout) findViewById(R.id.llContacts);
  34. llSettings = (LinearLayout) findViewById(R.id.llSettings);
  35. llChat.setOnClickListener(this);
  36. llFriends.setOnClickListener(this);
  37. llContacts.setOnClickListener(this);
  38. llSettings.setOnClickListener(this);
  39. ivChat = (ImageView) findViewById(R.id.ivChat);
  40. ivFriends = (ImageView) findViewById(R.id.ivFriends);
  41. ivContacts = (ImageView) findViewById(R.id.ivContacts);
  42. ivSettings = (ImageView) findViewById(R.id.ivSettings);
  43. tvChat = (TextView) findViewById(R.id.tvChat);
  44. tvFriends = (TextView) findViewById(R.id.tvFriends);
  45. tvContacts = (TextView) findViewById(R.id.tvContacts);
  46. tvSettings = (TextView) findViewById(R.id.tvSettings);
  47. ivChat.setSelected(true);
  48. tvChat.setSelected(true);
  49. ivCurrent = ivChat;
  50. tvCurrent = tvChat;
  51. viewPager.setOnPageChangeListener(new OnPageChangeListener() {
  52. @Override
  53. public void onPageSelected(int position) {
  54. changeTab(position);
  55. }
  56. @Override
  57. public void onPageScrolled(int arg0, float arg1, int arg2) {
  58. }
  59. @Override
  60. public void onPageScrollStateChanged(int arg0) {
  61. }
  62. });
  63. }
  64. private void initData() {
  65. LayoutInflater mInflater = LayoutInflater.from(this);
  66. View tab01 = mInflater.inflate(R.layout.tab01, null);
  67. View tab02 = mInflater.inflate(R.layout.tab02, null);
  68. View tab03 = mInflater.inflate(R.layout.tab03, null);
  69. View tab04 = mInflater.inflate(R.layout.tab04, null);
  70. views.add(tab01);
  71. views.add(tab02);
  72. views.add(tab03);
  73. views.add(tab04);
  74. MyPagerAdapter adapter = new MyPagerAdapter(views);
  75. viewPager.setAdapter(adapter);
  76. }
  77. @Override
  78. public void onClick(View v) {
  79. changeTab(v.getId());
  80. }
  81. private void changeTab(int id) {
  82. ivCurrent.setSelected(false);
  83. tvCurrent.setSelected(false);
  84. switch (id) {
  85. case R.id.llChat:
  86. viewPager.setCurrentItem(0);
  87. case 0:
  88. ivChat.setSelected(true);
  89. ivCurrent = ivChat;
  90. tvChat.setSelected(true);
  91. tvCurrent = tvChat;
  92. break;
  93. case R.id.llFriends:
  94. viewPager.setCurrentItem(1);
  95. case 1:
  96. ivFriends.setSelected(true);
  97. ivCurrent = ivFriends;
  98. tvFriends.setSelected(true);
  99. tvCurrent = tvFriends;
  100. break;
  101. case R.id.llContacts:
  102. viewPager.setCurrentItem(2);
  103. case 2:
  104. ivContacts.setSelected(true);
  105. ivCurrent = ivContacts;
  106. tvContacts.setSelected(true);
  107. tvCurrent = tvContacts;
  108. break;
  109. case R.id.llSettings:
  110. viewPager.setCurrentItem(3);
  111. case 3:
  112. ivSettings.setSelected(true);
  113. ivCurrent = ivSettings;
  114. tvSettings.setSelected(true);
  115. tvCurrent = tvSettings;
  116. break;
  117. default:
  118. break;
  119. }
  120. }
  121. }
这种方法一的方式就是提前用mInflater.inflate4个View丢到PagerAdapter里面,再给ViewPager设置Adapter
然后把点击底部Tab的事件和滑动ViewPager的事件(主要包括图片和文字seletor切换)整合在一起.
 
 

方法二. ViewPager + List<Fragment> + FragmentPagerAdapter或FragmentStatePagerAdapter

这种方法就很常见了
activity_main.xml和上文一样.
我们看MainActivity.java
  1. package com.yao.tab02;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import android.app.Activity;
  5. import android.app.Fragment;
  6. import android.os.Bundle;
  7. import android.support.v4.view.ViewPager;
  8. import android.support.v4.view.ViewPager.OnPageChangeListener;
  9. import android.view.View;
  10. import android.view.Window;
  11. import android.view.View.OnClickListener;
  12. import android.widget.ImageView;
  13. import android.widget.LinearLayout;
  14. import android.widget.TextView;
  15. public class MainActivity extends Activity implements OnClickListener {
  16. private List<Fragment> fragments = new ArrayList<Fragment>();
  17. private ViewPager viewPager;
  18. private LinearLayout llChat, llFriends, llContacts, llSettings;
  19. private ImageView ivChat, ivFriends, ivContacts, ivSettings, ivCurrent;
  20. private TextView tvChat, tvFriends, tvContacts, tvSettings, tvCurrent;
  21. @Override
  22. protected void onCreate(Bundle savedInstanceState) {
  23. super.onCreate(savedInstanceState);
  24. requestWindowFeature(Window.FEATURE_NO_TITLE);
  25. setContentView(R.layout.activity_main);
  26. initView();
  27. initData();
  28. }
  29. private void initView() {
  30. viewPager = (ViewPager) findViewById(R.id.viewPager);
  31. llChat = (LinearLayout) findViewById(R.id.llChat);
  32. llFriends = (LinearLayout) findViewById(R.id.llFriends);
  33. llContacts = (LinearLayout) findViewById(R.id.llContacts);
  34. llSettings = (LinearLayout) findViewById(R.id.llSettings);
  35. llChat.setOnClickListener(this);
  36. llFriends.setOnClickListener(this);
  37. llContacts.setOnClickListener(this);
  38. llSettings.setOnClickListener(this);
  39. ivChat = (ImageView) findViewById(R.id.ivChat);
  40. ivFriends = (ImageView) findViewById(R.id.ivFriends);
  41. ivContacts = (ImageView) findViewById(R.id.ivContacts);
  42. ivSettings = (ImageView) findViewById(R.id.ivSettings);
  43. tvChat = (TextView) findViewById(R.id.tvChat);
  44. tvFriends = (TextView) findViewById(R.id.tvFriends);
  45. tvContacts = (TextView) findViewById(R.id.tvContacts);
  46. tvSettings = (TextView) findViewById(R.id.tvSettings);
  47. ivChat.setSelected(true);
  48. tvChat.setSelected(true);
  49. ivCurrent = ivChat;
  50. tvCurrent = tvChat;
  51. viewPager.setOnPageChangeListener(new OnPageChangeListener() {
  52. @Override
  53. public void onPageSelected(int position) {
  54. changeTab(position);
  55. }
  56. @Override
  57. public void onPageScrolled(int arg0, float arg1, int arg2) {
  58. }
  59. @Override
  60. public void onPageScrollStateChanged(int arg0) {
  61. }
  62. });
  63. viewPager.setOffscreenPageLimit(2); //设置向左和向右都缓存limit个页面
  64. }
  65. private void initData() {
  66. Fragment chatFragment = new ChatFragment();
  67. Fragment friendsFragment = new FriendsFragment();
  68. Fragment contactsFragment = new ContactsFragment();
  69. Fragment settingsFragment = new SettingsFragment();
  70. fragments.add(chatFragment);
  71. fragments.add(friendsFragment);
  72. fragments.add(contactsFragment);
  73. fragments.add(settingsFragment);
  74. MyFragmentPagerAdapter adapter = new MyFragmentPagerAdapter(getFragmentManager(), fragments);
  75. //      MyFragmentStatePagerAdapter adapter = new MyFragmentStatePagerAdapter(getFragmentManager(), fragments);
  76. viewPager.setAdapter(adapter);
  77. }
  78. @Override
  79. public void onClick(View v) {
  80. changeTab(v.getId());
  81. }
  82. private void changeTab(int id) {
  83. ivCurrent.setSelected(false);
  84. tvCurrent.setSelected(false);
  85. switch (id) {
  86. case R.id.llChat:
  87. viewPager.setCurrentItem(0);
  88. case 0:
  89. ivChat.setSelected(true);
  90. ivCurrent = ivChat;
  91. tvChat.setSelected(true);
  92. tvCurrent = tvChat;
  93. break;
  94. case R.id.llFriends:
  95. viewPager.setCurrentItem(1);
  96. case 1:
  97. ivFriends.setSelected(true);
  98. ivCurrent = ivFriends;
  99. tvFriends.setSelected(true);
  100. tvCurrent = tvFriends;
  101. break;
  102. case R.id.llContacts:
  103. viewPager.setCurrentItem(2);
  104. case 2:
  105. ivContacts.setSelected(true);
  106. ivCurrent = ivContacts;
  107. tvContacts.setSelected(true);
  108. tvCurrent = tvContacts;
  109. break;
  110. case R.id.llSettings:
  111. viewPager.setCurrentItem(3);
  112. case 3:
  113. ivSettings.setSelected(true);
  114. ivCurrent = ivSettings;
  115. tvSettings.setSelected(true);
  116. tvCurrent = tvSettings;
  117. break;
  118. default:
  119. break;
  120. }
  121. }
  122. }
 
 

说明一:讲一下FragmentPagerAdapter 和 FragmentStatePagerAdapter 区别

1.FragmentStatePagerAdapter : 适合多个界面,类似于listView原理,离开视线就会被回收  会执行onDestroyView方法 onDestroy方法
2.FragmentPagerAdapter : 适合少量界面, 方便滑动  执行onDestroyView方法 不执行onDestroy方法
3.两者都会预先准备好并缓存上一个和下一个Fragment

说明二:重要说明:有个神方法viewPager.setOffscreenPageLimit(2); //设置向左和向右都缓存limit个页面.

             我也是很晚才发现有这个方法.下面4个Tab, 只要你设置这个值为3, 那4个Tab永远都会缓存着了.

变态说明:这里告诉大家一个小技巧.ViewPager是V4包里面的.用到的FragmentPagerAdapter和FragmentStatePagerAdapter也是V4包里面的.
                 如果我们不想用android.support.v4.app.Fragment, 那就可以自己复制出来一个FragmentPagerAdapter,然后把里面的Fragment改成android.app.Fragment.
                 连带FragmentManager和FragmentTransaction也要改成android.app包下的
 
 

暂时越过方法三的方法四. FragmentTabHost

跳过方法三,先讲方法四.方法四是代码量最少的方法.简单快捷轻便
item_tab.xml   这个是下面部分4个Tab中其中一个Tab的布局, 以此来FragmentTabHost会帮忙批量生产出4个Tab
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="wrap_content"
  5. android:gravity="center"
  6. android:orientation="vertical"
  7. android:padding="5dp" >
  8. <ImageView
  9. android:id="@+id/iv"
  10. android:layout_width="wrap_content"
  11. android:layout_height="wrap_content"
  12. android:background="#00000000"
  13. android:src="@drawable/tab_setting" />
  14. <TextView
  15. android:id="@+id/tv"
  16. android:layout_width="wrap_content"
  17. android:layout_height="wrap_content"
  18. android:textColor="@drawable/tab_textview" />
  19. </LinearLayout>
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. <LinearLayout
  7. android:layout_width="match_parent"
  8. android:layout_height="45dp"
  9. android:background="#0E6DB0"
  10. android:gravity="center"
  11. android:orientation="vertical" >
  12. <TextView
  13. android:layout_width="wrap_content"
  14. android:layout_height="wrap_content"
  15. android:layout_gravity="center"
  16. android:text="@string/app_name"
  17. android:textColor="#ffffff"
  18. android:textSize="20sp"
  19. android:textStyle="bold" />
  20. </LinearLayout>
  21. <FrameLayout
  22. android:id="@+id/flContainer"
  23. android:layout_width="match_parent"
  24. android:layout_height="0dp"
  25. android:layout_weight="1" >
  26. </FrameLayout>
  27. <com.yao.tab04.FragmentTabHost
  28. android:id="@+id/tabhost"
  29. android:layout_width="match_parent"
  30. android:layout_height="wrap_content"
  31. android:background="#0E6DB0" >
  32. </com.yao.tab04.FragmentTabHost>
  33. </LinearLayout>

MainActivity.java

  1. package com.yao.tab04;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.util.Log;
  5. import android.view.LayoutInflater;
  6. import android.view.View;
  7. import android.view.Window;
  8. import android.widget.ImageView;
  9. import android.widget.TabHost.OnTabChangeListener;
  10. import android.widget.TabHost.TabSpec;
  11. import android.widget.TextView;
  12. public class MainActivity extends Activity implements OnTabChangeListener {
  13. private FragmentTabHost tabHost;
  14. private String[] tabText = { "聊天", "朋友", "通讯录", "设置" };
  15. private int[] imageRes = new int[] { R.drawable.tab_chat, R.drawable.tab_friends, R.drawable.tab_contacts, R.drawable.tab_setting };
  16. private Class[] fragments = new Class[] { ChatFragment.class, FriendsFragment.class, ContactsFragment.class, SettingsFragment.class };
  17. @Override
  18. protected void onCreate(Bundle savedInstanceState) {
  19. super.onCreate(savedInstanceState);
  20. requestWindowFeature(Window.FEATURE_NO_TITLE);
  21. setContentView(R.layout.activity_main);
  22. tabHost = (FragmentTabHost) super.findViewById(R.id.tabhost);
  23. tabHost.setup(this, super.getFragmentManager(), R.id.flContainer);
  24. tabHost.getTabWidget().setDividerDrawable(null);
  25. tabHost.setOnTabChangedListener(this);
  26. initTab();
  27. }
  28. private void initTab() {
  29. for (int i = 0; i < tabText.length; i++) {
  30. View view = LayoutInflater.from(this).inflate(R.layout.item_tab, null);
  31. ((TextView) view.findViewById(R.id.tv)).setText(tabText[i]);
  32. ((ImageView) view.findViewById(R.id.iv)).setImageResource(imageRes[i]);
  33. TabSpec tabSpec = tabHost.newTabSpec(tabText[i]).setIndicator(view);
  34. tabHost.addTab(tabSpec, fragments[i], null);
  35. tabHost.setTag(i);
  36. }
  37. }
  38. //自动把getCurrentTabView下的所有子View的selected状态设为true. 牛逼!
  39. @Override
  40. public void onTabChanged(String tabId) {
  41. //首次打开自动会调用一下  首次自动输出tabId : 聊天
  42. Log.e("yao", "tabId : " + tabId);
  43. //      TabWidget tabWidget = tabHost.getTabWidget(); //获取整个底部Tab的布局, 可以通过tabWidget.getChildCount和tabWidget.getChildAt来获取某个子View
  44. //      int pos = tabHost.getCurrentTab(); //获取当前tab的位置
  45. //      View view = tabHost.getCurrentTabView(); //获取当前tab的view
  46. }
  47. }
说明一: 重要说明:有些博主还需要写一个未选中的图片ResId数组和一个选中的图片ResId数组.然后根据点击自己在代码上写把图片切换成选中状态.Navie.
              你只要传进去一组seletor图片,把文字颜色也设为seletor.FragmentTabHost叼的地方来了.它会自动把图片这个布局View下的所有子控件切换成selected状态.
              所以我代码这些相关的逻辑没写,还是会变色.
 
说明二: 业务逻辑写在onTabChanged.  一般用到的几个核心方法 已经写在上面了
说明三: TabHost好像不能设置导航栏在底部. 所以只能用FragmentTabHost.
说明四: 切到别的页面,当前这个页面会执行到onDestroyView方法,不会执行onDestroy方法.
 
 
 

方法三. 用fragmentTransaction的show和hide方法隐藏和显示Fragment

网上这种代码已有,但是大多数写的很乱.
大致思路整理一下就是如下.
  1. if (想要的fragment == null) {
  2. if (当前显示的fragment != null) {
  3. 隐藏当前fragment
  4. }
  5. 生产想要的fragment
  6. } else if (想要的fragment == 当前显示的fragment) {
  7. } else {
  8. 隐藏当前fragment
  9. 显示想要的fragment
  10. }

然后在中间插入该变化的资源selector代码

 
下面看代码.
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. <LinearLayout
  7. android:layout_width="match_parent"
  8. android:layout_height="45dp"
  9. android:background="#0E6DB0"
  10. android:gravity="center"
  11. android:orientation="vertical" >
  12. <TextView
  13. android:layout_width="wrap_content"
  14. android:layout_height="wrap_content"
  15. android:layout_gravity="center"
  16. android:text="@string/app_name"
  17. android:textColor="#ffffff"
  18. android:textSize="20sp"
  19. android:textStyle="bold" />
  20. </LinearLayout>
  21. <FrameLayout
  22. android:id="@+id/flContainer"
  23. android:layout_width="match_parent"
  24. android:layout_height="0dp"
  25. android:layout_weight="1" >
  26. </FrameLayout>
  27. <LinearLayout
  28. android:layout_width="match_parent"
  29. android:layout_height="55dp"
  30. android:background="#0E6DB0"
  31. android:orientation="horizontal" >
  32. <LinearLayout
  33. android:id="@+id/llChat"
  34. android:layout_width="0dp"
  35. android:layout_height="match_parent"
  36. android:layout_weight="1"
  37. android:gravity="center"
  38. android:orientation="vertical" >
  39. <ImageView
  40. android:id="@+id/ivChat"
  41. android:layout_width="wrap_content"
  42. android:layout_height="wrap_content"
  43. android:background="#00000000"
  44. android:src="@drawable/tab_chat" />
  45. <TextView
  46. android:id="@+id/tvChat"
  47. android:layout_width="wrap_content"
  48. android:layout_height="wrap_content"
  49. android:text="微信"
  50. android:textColor="@drawable/tab_textview" />
  51. </LinearLayout>
  52. <LinearLayout
  53. android:id="@+id/llFriends"
  54. android:layout_width="0dp"
  55. android:layout_height="match_parent"
  56. android:layout_weight="1"
  57. android:gravity="center"
  58. android:orientation="vertical" >
  59. <ImageView
  60. android:id="@+id/ivFriends"
  61. android:layout_width="wrap_content"
  62. android:layout_height="wrap_content"
  63. android:background="#00000000"
  64. android:src="@drawable/tab_friends" />
  65. <TextView
  66. android:id="@+id/tvFriends"
  67. android:layout_width="wrap_content"
  68. android:layout_height="wrap_content"
  69. android:text="朋友"
  70. android:textColor="@drawable/tab_textview" />
  71. </LinearLayout>
  72. <LinearLayout
  73. android:id="@+id/llContacts"
  74. android:layout_width="0dp"
  75. android:layout_height="match_parent"
  76. android:layout_weight="1"
  77. android:gravity="center"
  78. android:orientation="vertical" >
  79. <ImageView
  80. android:id="@+id/ivContacts"
  81. android:layout_width="wrap_content"
  82. android:layout_height="wrap_content"
  83. android:background="#00000000"
  84. android:src="@drawable/tab_contacts" />
  85. <TextView
  86. android:id="@+id/tvContacts"
  87. android:layout_width="wrap_content"
  88. android:layout_height="wrap_content"
  89. android:text="通讯录"
  90. android:textColor="@drawable/tab_textview" />
  91. </LinearLayout>
  92. <LinearLayout
  93. android:id="@+id/llSettings"
  94. android:layout_width="0dp"
  95. android:layout_height="match_parent"
  96. android:layout_weight="1"
  97. android:gravity="center"
  98. android:orientation="vertical" >
  99. <ImageView
  100. android:id="@+id/ivSettings"
  101. android:layout_width="wrap_content"
  102. android:layout_height="wrap_content"
  103. android:background="#00000000"
  104. android:src="@drawable/tab_setting" />
  105. <TextView
  106. android:id="@+id/tvSettings"
  107. android:layout_width="wrap_content"
  108. android:layout_height="wrap_content"
  109. android:text="设置"
  110. android:textColor="@drawable/tab_textview" />
  111. </LinearLayout>
  112. </LinearLayout>
  113. </LinearLayout>

本人核心封装

FragmentSwitchTool.java
  1. /**
  2. * FileName:FragmentSwitchTool.java
  3. * Copyright YaoDiWei All Rights Reserved.
  4. */
  5. package com.yao.tab03;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. import android.app.Fragment;
  9. import android.app.FragmentManager;
  10. import android.app.FragmentTransaction;
  11. import android.os.Bundle;
  12. import android.view.View;
  13. import android.view.View.OnClickListener;
  14. /**
  15. * @author YaoDiWei
  16. * @version
  17. */
  18. public class FragmentSwitchTool implements OnClickListener {
  19. private FragmentManager fragmentManager;
  20. private Fragment currentFragment;
  21. //  private View currentClickableView;
  22. private View[] currentSelectedView;
  23. private View[] clickableViews; //传入用于被点击的view,比如是一个LinearLayout
  24. private List<View[]> selectedViews; //传入用于被更改资源selected状态的view[], 比如一组View[]{TextView, ImageView}
  25. private Class<? extends Fragment>[] fragments;
  26. private Bundle[] bundles;
  27. private int containerId;
  28. private boolean showAnimator;
  29. public FragmentSwitchTool(FragmentManager fragmentManager, int containerId) {
  30. super();
  31. this.fragmentManager = fragmentManager;
  32. this.containerId = containerId;
  33. }
  34. public void setClickableViews(View... clickableViews) {
  35. this.clickableViews = clickableViews;
  36. for (View view : clickableViews) {
  37. view.setOnClickListener(this);
  38. }
  39. }
  40. public void setSelectedViews(List<View[]> selectedViews) {
  41. this.selectedViews = selectedViews;
  42. }
  43. public FragmentSwitchTool addSelectedViews(View... views){
  44. if (selectedViews == null) {
  45. selectedViews = new ArrayList<View[]>();
  46. }
  47. selectedViews.add(views);
  48. return this;
  49. }
  50. public void setFragments(Class<? extends Fragment>... fragments) {
  51. this.fragments = fragments;
  52. }
  53. public void setBundles(Bundle... bundles) {
  54. this.bundles = bundles;
  55. }
  56. public void changeTag(View v) {
  57. FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
  58. Fragment fragment = fragmentManager.findFragmentByTag(String.valueOf(v.getId()));
  59. for (int i = 0; i < clickableViews.length; i++) {
  60. if (v.getId() == clickableViews[i].getId()) {
  61. //过渡动画
  62. if (showAnimator) {
  63. int exitIndex = selectedViews.indexOf(currentSelectedView);
  64. //                  Log.e("yao", "enter : " + i + "   exit: " + exitIndex);
  65. if (i > exitIndex){
  66. fragmentTransaction.setCustomAnimations(R.anim.slide_right_in, R.anim.slide_left_out);
  67. } else if (i < exitIndex) {
  68. fragmentTransaction.setCustomAnimations(R.anim.slide_left_in, R.anim.slide_right_out);
  69. }
  70. }
  71. //过渡动画
  72. if (fragment == null) {
  73. if (currentFragment != null) {
  74. fragmentTransaction.hide(currentFragment);
  75. for (View view : currentSelectedView) {
  76. view.setSelected(false);
  77. }
  78. }
  79. try {
  80. fragment = fragments[i].newInstance();
  81. if (bundles != null && bundles[i] != null) {
  82. fragment.setArguments(bundles[i]);
  83. }
  84. } catch (InstantiationException e) {
  85. e.printStackTrace();
  86. } catch (IllegalAccessException e) {
  87. e.printStackTrace();
  88. }
  89. fragmentTransaction.add(containerId, fragment, String.valueOf(clickableViews[i].getId()));
  90. } else if (fragment == currentFragment) {
  91. } else {
  92. fragmentTransaction.hide(currentFragment);
  93. for (View view : currentSelectedView) {
  94. view.setSelected(false);
  95. }
  96. fragmentTransaction.show(fragment);
  97. }
  98. fragmentTransaction.commit();
  99. currentFragment = fragment;
  100. for (View view : selectedViews.get(i)) {
  101. view.setSelected(true);
  102. }
  103. currentSelectedView = selectedViews.get(i);
  104. break;
  105. }
  106. }
  107. }
  108. @Override
  109. public void onClick(View v)
  110. {
  111. changeTag(v);
  112. }
  113. }

MainActivity.java

  1. package com.yao.tab03;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.view.View;
  5. import android.view.Window;
  6. import android.widget.ImageView;
  7. import android.widget.LinearLayout;
  8. import android.widget.TextView;
  9. public class MainActivity extends Activity{
  10. private LinearLayout llChat, llFriends, llContacts, llSettings;
  11. private ImageView ivChat, ivFriends, ivContacts, ivSettings;
  12. private TextView tvChat, tvFriends, tvContacts, tvSettings;
  13. private FragmentSwitchTool tool;
  14. @Override
  15. protected void onCreate(Bundle savedInstanceState) {
  16. super.onCreate(savedInstanceState);
  17. requestWindowFeature(Window.FEATURE_NO_TITLE);
  18. setContentView(R.layout.activity_main);
  19. initView();
  20. tool = new FragmentSwitchTool(getFragmentManager(), R.id.flContainer);
  21. tool.setClickableViews(llChat, llFriends, llContacts, llSettings);
  22. tool.addSelectedViews(new View[]{ivChat, tvChat}).addSelectedViews(new View[]{ivFriends, tvFriends})
  23. .addSelectedViews(new View[]{ivContacts, tvContacts}).addSelectedViews(new View[]{ivSettings, tvSettings});
  24. tool.setFragments(ChatFragment.class, FriendsFragment.class, ContactsFragment.class, SettingsFragment.class);
  25. tool.changeTag(llChat);
  26. }
  27. private void initView() {
  28. llChat = (LinearLayout) findViewById(R.id.llChat);
  29. llFriends = (LinearLayout) findViewById(R.id.llFriends);
  30. llContacts = (LinearLayout) findViewById(R.id.llContacts);
  31. llSettings = (LinearLayout) findViewById(R.id.llSettings);
  32. ivChat = (ImageView) findViewById(R.id.ivChat);
  33. ivFriends = (ImageView) findViewById(R.id.ivFriends);
  34. ivContacts = (ImageView) findViewById(R.id.ivContacts);
  35. ivSettings = (ImageView) findViewById(R.id.ivSettings);
  36. tvChat = (TextView) findViewById(R.id.tvChat);
  37. tvFriends = (TextView) findViewById(R.id.tvFriends);
  38. tvContacts = (TextView) findViewById(R.id.tvContacts);
  39. tvSettings = (TextView) findViewById(R.id.tvSettings);
  40. }
  41. }
说明一: 重要说明:FragmentSwitchTool把所有的操作都封装好在里面了.所以以后只需要写一个布局文件(注意要写成seletor的形式). 
              在MainActivity中写几行给FragmentSwitchTool的传参就行.
说明二:  过渡动画有点糙,随便写的,可以删掉.
 

方法五.

Bottom Navigation是5.0(API level 21)新出的一种符合MD规范的导航栏规范。
注意这里说的是规范,所以当时并没有实现这个BottomNavigation这里有两篇文章可以看看。
原文: https://material.google.com/components/bottom-navigation.html
译文:https://modao.cc/posts/3068
但是谷歌并没有实现这个控件,所以目前民间有3个比较火的开源库,GitHub - aurelhubert/ahbottomnavigation,GitHub - roughike/BottomBar, Ashok-Varma/BottomNavigation。这3个库都很炫酷,动画很丰富。比如我有个小项目就用到了ahbottomnavigation。
 
然后在Android Support Library 25 后,Android 终于自己增加了一个控件 android.support.design.widget.BottomNavigationView。用法很简单,你甚至不用去看文档。直接在Android studio 里新建一个 BottomNavigation 的模板 Activity 就行。
然而官方这个相比网上那三个开源库,动画就相对朴素了。
 
 
 
 
总结: 
方法一:创建就会一次性加载完四个页面.适合简单的页面,比如app一开始的导航页.
方法二:给力的方法.适合能左右滑动的页面.可以自己定制缓存策略.配合神方法,也能一开始就加载全部页面.
方法三:最大的好处是, 用的才加载. 一旦加载就不删除. 切换只用hide和show,速度飞快. 当然你也可以自己定制适合自己的缓存策略.
方法四:简单快捷.代码少.但是切换速度理论不够方法三快.
方法五:符合MD设计的,希望自己的APP炫酷一点的.毫无疑问都应该用BottomNavigation规范的控件。
下载地址:
http://download.csdn.net/detail/alcoholdi/9565976

Android (争取做到)最全的底部导航栏实现方法的更多相关文章

  1. Android之RadioGroup+ViewPager制作的底部导航栏

    在日常开发中我们常常会用到类似微信或者QQ的底部导航.实现这样的效果有多种,今天就为大家介绍一种实现简单,可控性好的底部导航的实现方法. 首先创建activity_main.xml布局文件,里面主要由 ...

  2. cocos3.x 实现android沉浸式模式(全屏,隐藏导航栏即虚拟键)

    只有在Android 4.4及以上系统才支持沉浸式模式,修改 AppActivity代码如下: @Override public Cocos2dxGLSurfaceView onCreateView( ...

  3. Android学习总结——输入法将BottomNavigationBar(底部导航栏)顶上去的问题

    在应用清单中给当前<Activity>设置: android:windowSoftInputMode="adjustPan" 关于android:windowSoftI ...

  4. Flutter - 创建底部导航栏

    之前写过的一篇文章介绍了 Flutter - 创建横跨所有页面的侧滑菜单, 这次就一起来学习一下底部导航栏. 底部导航栏在ios平台上非常常见,app store就是这样的风格.还有就是大家最常用的微 ...

  5. Android应用底部导航栏(选项卡)实例

    现在很多android的应用都采用底部导航栏的功能,这样可以使得用户在使用过程中随意切换不同的页面,现在我采用TabHost组件来自定义一个底部的导航栏的功能. 我们先看下该demo实例的框架图: 其 ...

  6. Android 修改底部导航栏navigationbar的颜色

    Android 修改底部导航栏navigationbar的颜色 getWindow().setNavigationBarColor(Color.BLUE); //写法一 getWindow().set ...

  7. Android底部导航栏——FrameLayout + RadioGroup

    原创文章,转载请注明出处http://www.cnblogs.com/baipengzhan/p/6285881.html Android底部导航栏有多种实现方式,本文详细介绍FrameLayout ...

  8. Android底部导航栏创建——ViewPager + RadioGroup

    原创文章,引用请注明出处:http://www.cnblogs.com/baipengzhan/p/6270201.html Android底部导航栏有多种实现方式,本文详解其中的ViewPager ...

  9. Android学习笔记- Fragment实例 底部导航栏的实现

    1.要实现的效果图以及工程目录结构: 先看看效果图吧: 接着看看我们的工程的目录结构: 2.实现流程: Step 1:写下底部选项的一些资源文件 我们从图上可以看到,我们底部的每一项点击的时候都有不同 ...

随机推荐

  1. 处理html内容,获取纯文本

    import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import java.util.rege ...

  2. Sql Server 与 MySql 在使用 update inner join 时的区别

    Sql Server -- 不使用别名 UPDATE tb_User SET tb_User.pass = '' FROM tb_User usr INNER JOIN tb_Address addr ...

  3. (一)认识Sass和Compass

    第一章 Sass和Compass让样式表重焕青春 // 内容概要// 开始学习Sass和动态样式表// 用Sass更高效地写样式表// Compass简介// 用Compass迎接工程实践中的样式挑战 ...

  4. python内置函数每日一学 -- abs()

    abs(x) 官方文档解释: Return the absolute value of a number. The argument may be an integer or a floating p ...

  5. layer弹出框确定前验证:弹出消息框(弹出两个layer)

    作者QQ:1095737364 QQ群:123300273 欢迎加入! layer 弹出框中经常遇到要弹出表单进行修改数据, 因此在弹出框中的表单需要验证数据, 就需要在弹出一个layer, 默认的设 ...

  6. Codeforces Round #545 (Div. 1) 简要题解

    这里没有翻译 Codeforces Round #545 (Div. 1) T1 对于每行每列分别离散化,求出大于这个位置的数字的个数即可. # include <bits/stdc++.h&g ...

  7. 鼠标悬浮控制元素隐藏与显示 - css中鼠标的hover状态

    需求:当鼠标移动到一个元素A身上时,另外一个元素B显示. 实现原理: A元素与B元素有一个相同的父级. B元素默认隐藏,A元素默认显示. 当鼠标移动到A元素身上时,也可以看做是移动到了A元素的父级身上 ...

  8. SharePoint designer workflow给一个hyperlink类型得field赋值, How to set value to a hyperlink field by designer workflow

    通过worlfow给一个链接类型得field赋值: 格式是: {link}, {linkDisplayname} 一定要注意逗号后面有个空格. 举个栗子: 如果一个链接显示为 Approve / Re ...

  9. Linux 多个vi、vim进程编辑同一文件时的临时文件问题

    多个vi.vim进程编辑同一文件时的临时文件问题 by:授客 QQ:1033553122   使用vi.vim编辑文件,实际是先copy一份临时文件并映射到内存里进行编辑,所以你编辑的是临时文件,不是 ...

  10. Java虚拟机(二)对象的创建与OOP-Klass模型

    前言 在前一篇文章中我们学习了Java虚拟机的结构原理与运行时数据区域,那么我们大概知道了Java虚拟机的内存的概况,那么内存中的数据是如何创建和访问的呢?这篇文章会给你答案. 1.对象的创建 对象的 ...