原文出处

标题:Android底部导航栏,三种风格和实现
作者:阿飞__
原文链接:https://blog.csdn.net/afei__/article/details/80950288

一、效果图展示

2018070712270484.gif

如果动图没有动的话,也可以看下面这个静态图
image.png
以下挨个分析每个的实现,这里只做简单的效果展示,大家可以基于目前代码做二次开发。

二、BottomNavigationView

这是 Google 给我们提供的一个专门用于底部导航的 View,你只需要在新建 Activity 的时候选择 “Bottom Navigation Activity”,IDE 就会自动使用 BottomNavigationView 帮你生成好相应的代码了。

1.在 xml 中使用

  1. <android.support.design.widget.BottomNavigationView
  2. android:id="@+id/navigation"
  3. android:layout_width="0dp"
  4. android:layout_height="wrap_content"
  5. android:layout_marginEnd="0dp"
  6. android:layout_marginStart="0dp"
  7. android:background="?android:attr/windowBackground"
  8. app:layout_constraintBottom_toBottomOf="parent"
  9. app:layout_constraintLeft_toLeftOf="parent"
  10. app:layout_constraintRight_toRightOf="parent"
  11. app:menu="@menu/navigation" />

这里面唯一要注意的就是 app:menu 属性了,它指定了你的导航栏显示的页面菜单是怎样的。

2. menu 的布局文件

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <menu xmlns:android="http://schemas.android.com/apk/res/android">
  3. <item
  4. android:id="@+id/navigation_home"
  5. android:icon="@drawable/ic_home_black_24dp"
  6. android:title="@string/title_home" />
  7. <item
  8. android:id="@+id/navigation_dashboard"
  9. android:icon="@drawable/ic_dashboard_black_24dp"
  10. android:title="@string/title_dashboard" />
  11. <item
  12. android:id="@+id/navigation_notifications"
  13. android:icon="@drawable/ic_notifications_black_24dp"
  14. android:title="@string/title_notifications" />
  15. </menu>

3. 在 Activity 中调用

  1. private TextView mTextMessage;
  2. private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
  3. = new BottomNavigationView.OnNavigationItemSelectedListener() {
  4. @Override
  5. public boolean onNavigationItemSelected(@NonNull MenuItem item) {
  6. switch (item.getItemId()) {
  7. case R.id.navigation_home:
  8. mTextMessage.setText(R.string.title_home);
  9. return true;
  10. case R.id.navigation_dashboard:
  11. mTextMessage.setText(R.string.title_dashboard);
  12. return true;
  13. case R.id.navigation_notifications:
  14. mTextMessage.setText(R.string.title_notifications);
  15. return true;
  16. }
  17. return false;
  18. }
  19. };
  20. @Override
  21. protected void onCreate(Bundle savedInstanceState) {
  22. super.onCreate(savedInstanceState);
  23. setContentView(R.layout.activity_style1);
  24. mTextMessage = findViewById(R.id.message);
  25. BottomNavigationView navigation = findViewById(R.id.navigation);
  26. navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
  27. }

这里的演示 code 都是 IDE 自动生成的,由于 BottomNavigationView 目前我还没有在项目中实际使用过,这里不做过多分析,使用起来不难,以上代码已经足以满足我们的基本使用要求了。

三、RadioGroup + ViewPager

这是一种比较常见了的,下面 4 个 tab 的导航按钮,可以切换不同的页面,这里页面使用了 ViewPager + Fragment 的组合,实现了滑动的页面效果,也可以不使用 ViewPager,这个根据产品的定义来使用即可。

1. 布局文件

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. tools:context=".style2.Style2Activity">
  7. <android.support.v4.view.ViewPager
  8. android:id="@+id/fragment_vp"
  9. android:layout_width="match_parent"
  10. android:layout_height="match_parent"
  11. android:layout_above="@+id/tabs_rg" />
  12. <RadioGroup
  13. android:id="@+id/tabs_rg"
  14. android:layout_width="match_parent"
  15. android:layout_height="56dp"
  16. android:layout_alignParentBottom="true"
  17. android:background="#dcdcdc"
  18. android:orientation="horizontal">
  19. <RadioButton
  20. android:id="@+id/today_tab"
  21. style="@style/Custom.TabRadioButton"
  22. android:checked="true"
  23. android:drawableTop="@drawable/tab_sign_selector"
  24. android:text="今日" />
  25. <RadioButton
  26. android:id="@+id/record_tab"
  27. style="@style/Custom.TabRadioButton"
  28. android:drawableTop="@drawable/tab_record_selector"
  29. android:text="记录" />
  30. <RadioButton
  31. android:id="@+id/contact_tab"
  32. style="@style/Custom.TabRadioButton"
  33. android:drawableTop="@drawable/tab_contact_selector"
  34. android:text="通讯录" />
  35. <RadioButton
  36. android:id="@+id/settings_tab"
  37. style="@style/Custom.TabRadioButton"
  38. android:drawableTop="@drawable/tab_setting_selector"
  39. android:text="设置" />
  40. </RadioGroup>
  41. </RelativeLayout>

2. Activity 类

  1. public class Style2Activity extends AppCompatActivity {
  2. private ViewPager mViewPager;
  3. private RadioGroup mTabRadioGroup;
  4. private List<Fragment> mFragments;
  5. private FragmentPagerAdapter mAdapter;
  6. @Override
  7. protected void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.activity_style2);
  10. initView();
  11. }
  12. private void initView() {
  13. // find view
  14. mViewPager = findViewById(R.id.fragment_vp);
  15. mTabRadioGroup = findViewById(R.id.tabs_rg);
  16. // init fragment
  17. mFragments = new ArrayList<>(4);
  18. mFragments.add(BlankFragment.newInstance("今日"));
  19. mFragments.add(BlankFragment.newInstance("记录"));
  20. mFragments.add(BlankFragment.newInstance("通讯录"));
  21. mFragments.add(BlankFragment.newInstance("设置"));
  22. // init view pager
  23. mAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), mFragments);
  24. mViewPager.setAdapter(mAdapter);
  25. // register listener
  26. mViewPager.addOnPageChangeListener(mPageChangeListener);
  27. mTabRadioGroup.setOnCheckedChangeListener(mOnCheckedChangeListener);
  28. }
  29. @Override
  30. protected void onDestroy() {
  31. super.onDestroy();
  32. mViewPager.removeOnPageChangeListener(mPageChangeListener);
  33. }
  34. private ViewPager.OnPageChangeListener mPageChangeListener = new ViewPager.OnPageChangeListener() {
  35. @Override
  36. public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
  37. }
  38. @Override
  39. public void onPageSelected(int position) {
  40. RadioButton radioButton = (RadioButton) mTabRadioGroup.getChildAt(position);
  41. radioButton.setChecked(true);
  42. }
  43. @Override
  44. public void onPageScrollStateChanged(int state) {
  45. }
  46. };
  47. private RadioGroup.OnCheckedChangeListener mOnCheckedChangeListener = new RadioGroup.OnCheckedChangeListener() {
  48. @Override
  49. public void onCheckedChanged(RadioGroup group, int checkedId) {
  50. for (int i = 0; i < group.getChildCount(); i++) {
  51. if (group.getChildAt(i).getId() == checkedId) {
  52. mViewPager.setCurrentItem(i);
  53. return;
  54. }
  55. }
  56. }
  57. };
  58. private class MyFragmentPagerAdapter extends FragmentPagerAdapter {
  59. private List<Fragment> mList;
  60. public MyFragmentPagerAdapter(FragmentManager fm, List<Fragment> list) {
  61. super(fm);
  62. this.mList = list;
  63. }
  64. @Override
  65. public Fragment getItem(int position) {
  66. return this.mList == null ? null : this.mList.get(position);
  67. }
  68. @Override
  69. public int getCount() {
  70. return this.mList == null ? 0 : this.mList.size();
  71. }
  72. }
  73. }

这里唯一注意点的就是两个监听事件,要实现底部导航按钮和页面的联动。

四、带页面跳转功能的底部导航

很多 APP 的底部导航栏中间有一个很大的按钮,点击后通常是打开一个新的页面,这里我们要实现的就是这种底部导航。

依旧是使用 RadioGroup 来做,只不过中间一个 tab 我们先用一个空的 View 来占位,然后在这个 View 的位置放置一个较大的按钮来覆盖住。

  1. 布局文件

    1. <?xml version="1.0" encoding="utf-8"?>
    2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3. xmlns:tools="http://schemas.android.com/tools"
    4. android:layout_width="match_parent"
    5. android:layout_height="match_parent"
    6. tools:context=".style3.Style3Activity">
    7. <FrameLayout
    8. android:id="@+id/fragment_container"
    9. android:layout_width="match_parent"
    10. android:layout_height="match_parent"
    11. android:layout_above="@+id/tabs_rg" />
    12. <RadioGroup
    13. android:id="@+id/tabs_rg"
    14. android:layout_width="match_parent"
    15. android:layout_height="56dp"
    16. android:layout_alignParentBottom="true"
    17. android:background="#dcdcdc"
    18. android:orientation="horizontal">
    19. <RadioButton
    20. android:id="@+id/today_tab"
    21. style="@style/Custom.TabRadioButton"
    22. android:checked="true"
    23. android:drawableTop="@drawable/tab_sign_selector"
    24. android:text="今日" />
    25. <RadioButton
    26. android:id="@+id/record_tab"
    27. style="@style/Custom.TabRadioButton"
    28. android:drawableTop="@drawable/tab_record_selector"
    29. android:text="记录" />
    30. <View style="@style/Custom.TabRadioButton" />
    31. <RadioButton
    32. android:id="@+id/contact_tab"
    33. style="@style/Custom.TabRadioButton"
    34. android:drawableTop="@drawable/tab_contact_selector"
    35. android:text="通讯录" />
    36. <RadioButton
    37. android:id="@+id/settings_tab"
    38. style="@style/Custom.TabRadioButton"
    39. android:drawableTop="@drawable/tab_setting_selector"
    40. android:text="设置" />
    41. </RadioGroup>
    42. <ImageView
    43. android:id="@+id/sign_iv"
    44. android:layout_width="80dp"
    45. android:layout_height="80dp"
    46. android:layout_alignParentBottom="true"
    47. android:layout_centerHorizontal="true"
    48. android:background="@android:color/transparent"
    49. android:src="@mipmap/sign" />
    50. </RelativeLayout>

    2. Activity 类

    ```java public class Style3Activity extends AppCompatActivity {

    private RadioGroup mTabRadioGroup; private SparseArray mFragmentSparseArray;

    @Override protected void onCreate(Bundle savedInstanceState) {

    1. super.onCreate(savedInstanceState);
    2. setContentView(R.layout.activity_style3);
    3. initView();

    }

    private void initView() {

    1. mTabRadioGroup = findViewById(R.id.tabs_rg);
    2. mFragmentSparseArray = new SparseArray<>();
    3. mFragmentSparseArray.append(R.id.today_tab, BlankFragment.newInstance("今日"));
    4. mFragmentSparseArray.append(R.id.record_tab, BlankFragment.newInstance("记录"));
    5. mFragmentSparseArray.append(R.id.contact_tab, BlankFragment.newInstance("通讯录"));
    6. mFragmentSparseArray.append(R.id.settings_tab, BlankFragment.newInstance("设置"));
    7. mTabRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
    8. @Override
    9. public void onCheckedChanged(RadioGroup group, int checkedId) {
    10. // 具体的fragment切换逻辑可以根据应用调整,例如使用show()/hide()
    11. getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
    12. mFragmentSparseArray.get(checkedId)).commit();
    13. }
    14. });
    15. // 默认显示第一个
    16. getSupportFragmentManager().beginTransaction().add(R.id.fragment_container,
    17. mFragmentSparseArray.get(R.id.today_tab)).commit();
    18. findViewById(R.id.sign_iv).setOnClickListener(new View.OnClickListener() {
    19. @Override
    20. public void onClick(View v) {
    21. startActivity(new Intent(Style3Activity.this, SignActivity.class));
    22. }
    23. });

    }

} ``` 注意:
如果这里你也想使用 ViewPager 来展示 Fragment 的话,一定要注意这里的 RadioGroup 中间有一个占位的 View,即两者的监听事件里,实现联动时要考虑多个这个 View 的存在。

代码地址: https://gitee.com/afei_/BottomTabbar