当前位置:   article > 正文

Android 底部导航菜单栏的两种实现方式(ViewPage、Fragment)(仿微信界面)_android微信底部导航

android微信底部导航

一、实现效果

    

二、思路分析 

三、实现方式1(ViewPager方式)

1.代码结构

2.代码文件

2.1 顶部 activity_top.xml

  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:background="#ffffff"
  6. android:paddingTop="10dp"
  7. android:paddingLeft="10dp"
  8. android:layout_height="45dp">
  9. <TextView
  10. android:id="@+id/title"
  11. android:layout_width="wrap_content"
  12. android:layout_height="wrap_content"
  13. android:text="微信"
  14. android:textColor="#1B940A"
  15. android:textSize="16dp" />
  16. </RelativeLayout>

2.2 底部 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="#ffffff"
  6. android:padding="5dp"
  7. >
  8. <LinearLayout
  9. android:id="@+id/ll_home"
  10. android:layout_width="0dp"
  11. android:layout_height="wrap_content"
  12. android:layout_weight="1"
  13. android:gravity="center"
  14. android:orientation="vertical">
  15. <ImageView
  16. android:id="@+id/img_home"
  17. android:layout_width="24dp"
  18. android:layout_height="24dp"
  19. android:src="@mipmap/home" />
  20. <TextView
  21. android:id="@+id/txt_home"
  22. android:layout_width="wrap_content"
  23. android:layout_height="wrap_content"
  24. android:layout_marginTop="3dp"
  25. android:text="@string/txt_nav_home"
  26. android:textSize="12dp"
  27. android:textColor="#888888"
  28. />
  29. </LinearLayout>
  30. <LinearLayout
  31. android:id="@+id/ll_news"
  32. android:layout_width="0dp"
  33. android:layout_height="wrap_content"
  34. android:layout_weight="1"
  35. android:gravity="center"
  36. android:orientation="vertical">
  37. <ImageView
  38. android:id="@+id/img_news"
  39. android:layout_width="24dp"
  40. android:layout_height="24dp"
  41. android:src="@mipmap/news_index" />
  42. <TextView
  43. android:id="@+id/txt_news"
  44. android:layout_width="wrap_content"
  45. android:layout_height="wrap_content"
  46. android:layout_marginTop="3dp"
  47. android:text="@string/txt_nav_news"
  48. android:textSize="12dp"
  49. android:textColor="#888888"
  50. />
  51. </LinearLayout>
  52. <LinearLayout
  53. android:id="@+id/ll_friend"
  54. android:layout_width="0dp"
  55. android:layout_height="wrap_content"
  56. android:layout_weight="1"
  57. android:gravity="center"
  58. android:orientation="vertical">
  59. <ImageView
  60. android:id="@+id/img_friend"
  61. android:layout_width="24dp"
  62. android:layout_height="24dp"
  63. android:src="@mipmap/news_add" />
  64. <TextView
  65. android:id="@+id/txt_friend"
  66. android:layout_width="wrap_content"
  67. android:layout_height="wrap_content"
  68. android:layout_marginTop="3dp"
  69. android:text="@string/txt_nav_friend"
  70. android:textSize="12dp"
  71. android:textColor="#888888"
  72. />
  73. </LinearLayout>
  74. <LinearLayout
  75. android:id="@+id/ll_user"
  76. android:layout_width="0dp"
  77. android:layout_height="wrap_content"
  78. android:layout_weight="1"
  79. android:gravity="center"
  80. android:orientation="vertical">
  81. <ImageView
  82. android:id="@+id/img_user"
  83. android:layout_width="24dp"
  84. android:layout_height="24dp"
  85. android:src="@mipmap/phone" />
  86. <TextView
  87. android:id="@+id/txt_user"
  88. android:layout_width="wrap_content"
  89. android:layout_height="wrap_content"
  90. android:layout_marginTop="3dp"
  91. android:text="@string/txt_nav_user"
  92. android:textSize="12dp"
  93. android:textColor="#888888"
  94. />
  95. </LinearLayout>
  96. </LinearLayout>

2.3 主视图 activity_main.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. android:orientation="vertical"
  8. tools:context=".MainActivity">
  9. <!--这里有个小技巧,把底部菜单栏的每一个小的LinearLayout的宽度都设置成0dp,然后用weight权重去分配它,中间内容区域也是把高度设置成0dp,然后用weight权重去分配它。(weight默认是把界面里空闲的位置作为划分位置,所以这里的宽度或者高度要注意设置成0dp)-->
  10. <include layout="@layout/activity_top" />
  11. <androidx.viewpager.widget.ViewPager
  12. android:id="@+id/vp_content"
  13. android:layout_width="match_parent"
  14. android:layout_height="0dp"
  15. android:layout_weight="1"
  16. android:background="#ffffff"
  17. tools:ignore="MissingConstraints"></androidx.viewpager.widget.ViewPager>
  18. <include layout="@layout/activity_bottom" />
  19. </LinearLayout>
这里有个小技巧,把底部菜单栏的每一个小的LinearLayout的宽度都设置成0dp,然后用weight权重去分配它,中间内容区域也是把高度设置成0dp,然后用weight权重去分配它。(weight默认是把界面里空闲的位置作为划分位置,所以这里的宽度或者高度要注意设置成0dp)

2.4 分页视图 page_home.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="match_parent"
  5. tools:context=".ui.HomeActivity">
  6. <TextView
  7. android:id="@+id/txt_home_title"
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:layout_centerInParent="true"
  11. android:text="我是01"
  12. android:textColor="#1B940A"
  13. android:textSize="30dp" />
  14. </RelativeLayout>

2.5 ContentAdapter.java:ViewPager需配合一个Adapter使用,所以需先自定义一个Adapter。

  1. package com.rc.bottombar;
  2. import java.util.List;
  3. import android.view.View;
  4. import android.view.ViewGroup;
  5. import androidx.viewpager.widget.PagerAdapter;
  6. public class ContentAdapter extends PagerAdapter {
  7. private List<View> views;
  8. public ContentAdapter(List<View> views) {
  9. this.views = views;
  10. }
  11. @Override
  12. public int getCount() {
  13. return views.size();
  14. }
  15. @Override
  16. public boolean isViewFromObject(View arg0, Object arg1) {
  17. return arg0 == arg1;
  18. }
  19. @Override
  20. public Object instantiateItem(ViewGroup container, int position) {
  21. View view = views.get(position);
  22. container.addView(view);
  23. return view;
  24. }
  25. @Override
  26. public void destroyItem(ViewGroup container, int position, Object object) {
  27. container.removeView(views.get(position));
  28. }
  29. }

2.6 MainActivity.java

  1. package com.rc.bottombar;
  2. import androidx.viewpager.widget.ViewPager;
  3. import android.app.Activity;
  4. import android.graphics.Color;
  5. import android.os.Bundle;
  6. import android.view.View;
  7. import android.widget.ImageView;
  8. import android.widget.LinearLayout;
  9. import android.widget.TextView;
  10. import com.rc.bottombar.ui.HomeActivity;
  11. import java.util.ArrayList;
  12. import java.util.List;
  13. public class MainActivity extends Activity implements View.OnClickListener, ViewPager.OnPageChangeListener {
  14. private TextView txt_title;
  15. // 底部菜单4个Linearlayout
  16. private LinearLayout ll_home;
  17. private LinearLayout ll_address;
  18. private LinearLayout ll_friend;
  19. private LinearLayout ll_setting;
  20. // 底部菜单4个ImageView
  21. private ImageView img_home;
  22. private ImageView img_news;
  23. private ImageView img_friend;
  24. private ImageView img_user;
  25. // 底部菜单4个菜单标题
  26. private TextView txt_home;
  27. private TextView txt_news;
  28. private TextView txt_friend;
  29. private TextView txt_user;
  30. // 中间内容区域
  31. private ViewPager viewPager;
  32. // ViewPager适配器ContentAdapter
  33. private ContentAdapter adapter;
  34. private List<View> views;
  35. @Override
  36. protected void onCreate(Bundle savedInstanceState) {
  37. super.onCreate(savedInstanceState);
  38. setContentView(R.layout.activity_main);
  39. initView();// 初始化控件
  40. initEvent();// 设置按钮监听
  41. txt_title.setText(R.string.txt_nav_home);
  42. txt_home.setTextColor(0xff1B940A);
  43. }
  44. private void initEvent() {
  45. ll_home.setOnClickListener(this);
  46. ll_address.setOnClickListener(this);
  47. ll_friend.setOnClickListener(this);
  48. ll_setting.setOnClickListener(this);
  49. viewPager.setOnPageChangeListener(this);
  50. }
  51. private void initView() {
  52. txt_title = findViewById(R.id.title);
  53. // 底部菜单4个Linearlayout
  54. ll_home = findViewById(R.id.ll_home);
  55. ll_address = findViewById(R.id.ll_news);
  56. ll_friend = findViewById(R.id.ll_friend);
  57. ll_setting = findViewById(R.id.ll_user);
  58. // 底部菜单4个ImageView
  59. img_home = findViewById(R.id.img_home);
  60. img_news = findViewById(R.id.img_news);
  61. img_friend = findViewById(R.id.img_friend);
  62. img_user = findViewById(R.id.img_user);
  63. // 底部菜单4个菜单标题
  64. txt_home = findViewById(R.id.txt_home);
  65. txt_news = findViewById(R.id.txt_news);
  66. txt_friend = findViewById(R.id.txt_friend);
  67. txt_user = findViewById(R.id.txt_user);
  68. // 中间内容区域ViewPager
  69. viewPager = findViewById(R.id.vp_content);
  70. // 适配器
  71. View page_home = View.inflate(MainActivity.this, R.layout.page_home, null);
  72. View page_news = View.inflate(MainActivity.this, R.layout.page_news, null);
  73. View page_friend = View.inflate(MainActivity.this, R.layout.page_friend, null);
  74. View page_user = View.inflate(MainActivity.this, R.layout.page_user, null);
  75. views = new ArrayList<View>();
  76. views.add(page_home);
  77. views.add(page_news);
  78. views.add(page_friend);
  79. views.add(page_user);
  80. adapter = new ContentAdapter(views);
  81. viewPager.setAdapter(adapter);
  82. }
  83. @Override
  84. public void onClick(View v) {
  85. switch (v.getId()) {
  86. case R.id.ll_home:
  87. restartBotton();
  88. txt_title.setText(R.string.txt_nav_home);
  89. txt_home.setTextColor(0xff1B940A);
  90. viewPager.setCurrentItem(0);
  91. break;
  92. case R.id.ll_news:
  93. restartBotton();
  94. txt_title.setText(R.string.txt_nav_news);
  95. txt_news.setTextColor(0xff1B940A);
  96. viewPager.setCurrentItem(1);
  97. break;
  98. case R.id.ll_friend:
  99. restartBotton();
  100. txt_title.setText(R.string.txt_nav_friend);
  101. txt_friend.setTextColor(0xff1B940A);
  102. viewPager.setCurrentItem(2);
  103. break;
  104. case R.id.ll_user:
  105. restartBotton();
  106. txt_title.setText(R.string.txt_nav_user);
  107. txt_user.setTextColor(0xff1B940A);
  108. viewPager.setCurrentItem(3);
  109. break;
  110. default:
  111. break;
  112. }
  113. }
  114. @Override
  115. public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
  116. }
  117. @Override
  118. public void onPageSelected(int position) {
  119. restartBotton();
  120. switch (position) {
  121. case 0:
  122. txt_title.setText(R.string.txt_nav_home);
  123. txt_home.setTextColor(0xff1B940A);
  124. break;
  125. case 1:
  126. txt_title.setText(R.string.txt_nav_news);
  127. txt_news.setTextColor(0xff1B940A);
  128. break;
  129. case 2:
  130. txt_title.setText(R.string.txt_nav_friend);
  131. txt_friend.setTextColor(0xff1B940A);
  132. break;
  133. case 3:
  134. txt_title.setText(R.string.txt_nav_user);
  135. txt_user.setTextColor(0xff1B940A);
  136. break;
  137. default:
  138. break;
  139. }
  140. }
  141. @Override
  142. public void onPageScrollStateChanged(int state) {
  143. }
  144. //重置链接样式
  145. private void restartBotton() {
  146. txt_home.setTextColor(Color.parseColor("#888888"));
  147. txt_news.setTextColor(Color.parseColor("#888888"));
  148. txt_friend.setTextColor(Color.parseColor("#888888"));
  149. txt_user.setTextColor(Color.parseColor("#888888"));
  150. }
  151. }

注意事项:

1.需实现视图点击事件和ViewPager切换事件,implements View.OnClickListener, ViewPager.OnPageChangeListener。

2.initEvent()方法中给控件绑定事件后,下面的Listener才捕捉得到。

3.上面代码只切换选中菜单文字的效果,选中图片也是可以切换的,暂忽略。

四、实现方式2(Fragment方式)

1.布局文件基本没变化,只是把主界面的ViewPager改成了FramLayout,其他文件保持一致,就不贴出来了。

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout 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. android:orientation="vertical"
  7. tools:context=".MainActivity">
  8. <!--这里有个小技巧,把底部菜单栏的每一个小的LinearLayout的宽度都设置成0dp,然后用weight权重去分配它,
  9. 中间内容区域也是把高度设置成0dp,然后用weight权重去分配它。
  10. (weight默认是把界面里空闲的位置作为划分位置,所以这里的宽度或者高度要注意设置成0dp)-->
  11. <include layout="@layout/activity_top" />
  12. <FrameLayout
  13. android:id="@+id/fl_content"
  14. android:layout_width="match_parent"
  15. android:background="#ffffff"
  16. android:layout_height="0dp"
  17. android:layout_weight="1" >
  18. </FrameLayout>
  19. <include layout="@layout/activity_bottom" />
  20. </LinearLayout>

2.新增4个Fragment类,结构如下图:

以HomeFragment.java 为例,其他类似。

  1. package com.rc.bottombar.ui;
  2. import android.app.Fragment;
  3. import android.os.Bundle;
  4. import android.view.LayoutInflater;
  5. import android.view.View;
  6. import android.view.ViewGroup;
  7. import android.widget.TextView;
  8. import androidx.annotation.Nullable;
  9. import com.rc.bottombar.R;
  10. import java.text.SimpleDateFormat;
  11. import java.util.Date;
  12. public class HomeFragment extends Fragment {
  13. View view;
  14. TextView title;
  15. @Override
  16. public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
  17. view = inflater.inflate(R.layout.page_home, container, false);
  18. title = view.findViewById(R.id.txt_home_title);
  19. title.setText("我是" + getResources().getString(R.string.txt_nav_home));
  20. return view;
  21. }
  22. public void Load() {
  23. //title.setText("当前时间:\n" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
  24. }
  25. }

 3.MainActivity.java

  1. package com.rc.bottombar;
  2. import android.app.Activity;
  3. import android.app.Fragment;
  4. import android.app.FragmentManager;
  5. import android.app.FragmentTransaction;
  6. import android.graphics.Color;
  7. import android.os.Bundle;
  8. import android.view.View;
  9. import android.widget.ImageView;
  10. import android.widget.LinearLayout;
  11. import android.widget.TextView;
  12. import com.rc.bottombar.ui.FriendFragment;
  13. import com.rc.bottombar.ui.HomeFragment;
  14. import com.rc.bottombar.ui.NewsFragment;
  15. import com.rc.bottombar.ui.UserFragment;
  16. public class MainActivity extends Activity implements View.OnClickListener {
  17. private TextView txt_title;
  18. // 底部菜单4个Linearlayout
  19. private LinearLayout ll_home;
  20. private LinearLayout ll_address;
  21. private LinearLayout ll_friend;
  22. private LinearLayout ll_setting;
  23. // 底部菜单4个ImageView
  24. private ImageView img_home;
  25. private ImageView img_news;
  26. private ImageView img_friend;
  27. private ImageView img_user;
  28. // 底部菜单4个菜单标题
  29. private TextView txt_home;
  30. private TextView txt_news;
  31. private TextView txt_friend;
  32. private TextView txt_user;
  33. // 4个Fragment
  34. private HomeFragment homeFragment;
  35. private Fragment newsFragment;
  36. private Fragment friendFragment;
  37. private Fragment userFragment;
  38. @Override
  39. protected void onCreate(Bundle savedInstanceState) {
  40. super.onCreate(savedInstanceState);
  41. setContentView(R.layout.activity_main);
  42. initView();// 初始化控件
  43. initEvent();// 设置按钮监听
  44. // 初始化并设置当前Fragment
  45. initFragment(0);
  46. }
  47. private void initEvent() {
  48. ll_home.setOnClickListener(this);
  49. ll_address.setOnClickListener(this);
  50. ll_friend.setOnClickListener(this);
  51. ll_setting.setOnClickListener(this);
  52. }
  53. private void initView() {
  54. txt_title = findViewById(R.id.title);
  55. // 底部菜单4个Linearlayout
  56. ll_home = findViewById(R.id.ll_home);
  57. ll_address = findViewById(R.id.ll_news);
  58. ll_friend = findViewById(R.id.ll_friend);
  59. ll_setting = findViewById(R.id.ll_user);
  60. // 底部菜单4个ImageView
  61. img_home = findViewById(R.id.img_home);
  62. img_news = findViewById(R.id.img_news);
  63. img_friend = findViewById(R.id.img_friend);
  64. img_user = findViewById(R.id.img_user);
  65. // 底部菜单4个菜单标题
  66. txt_home = findViewById(R.id.txt_home);
  67. txt_news = findViewById(R.id.txt_news);
  68. txt_friend = findViewById(R.id.txt_friend);
  69. txt_user = findViewById(R.id.txt_user);
  70. }
  71. @Override
  72. public void onClick(View v) {
  73. switch (v.getId()) {
  74. case R.id.ll_home:
  75. restartBotton();
  76. txt_title.setText(R.string.txt_nav_home);
  77. txt_home.setTextColor(0xff1B940A);
  78. initFragment(0);
  79. break;
  80. case R.id.ll_news:
  81. restartBotton();
  82. txt_title.setText(R.string.txt_nav_news);
  83. txt_news.setTextColor(0xff1B940A);
  84. initFragment(1);
  85. break;
  86. case R.id.ll_friend:
  87. restartBotton();
  88. txt_title.setText(R.string.txt_nav_friend);
  89. txt_friend.setTextColor(0xff1B940A);
  90. initFragment(2);
  91. break;
  92. case R.id.ll_user:
  93. restartBotton();
  94. txt_title.setText(R.string.txt_nav_user);
  95. txt_user.setTextColor(0xff1B940A);
  96. initFragment(3);
  97. break;
  98. default:
  99. break;
  100. }
  101. }
  102. private void initFragment(int index) {
  103. FragmentManager fragmentManager = getFragmentManager();
  104. FragmentTransaction transaction = fragmentManager.beginTransaction();
  105. hideFragment(transaction);
  106. switch (index) {
  107. case 0:
  108. if (homeFragment == null) {
  109. homeFragment = new HomeFragment();
  110. transaction.add(R.id.fl_content, homeFragment);
  111. } else {
  112. homeFragment.Load();//加载数据
  113. transaction.show(homeFragment);
  114. }
  115. break;
  116. case 1:
  117. if (newsFragment == null) {
  118. newsFragment = new NewsFragment();
  119. transaction.add(R.id.fl_content, newsFragment);
  120. } else {
  121. transaction.show(newsFragment);
  122. }
  123. break;
  124. case 2:
  125. if (friendFragment == null) {
  126. friendFragment = new FriendFragment();
  127. transaction.add(R.id.fl_content, friendFragment);
  128. } else {
  129. transaction.show(friendFragment);
  130. }
  131. break;
  132. case 3:
  133. if (userFragment == null) {
  134. userFragment = new UserFragment();
  135. transaction.add(R.id.fl_content, userFragment);
  136. } else {
  137. transaction.show(userFragment);
  138. }
  139. break;
  140. default:
  141. break;
  142. }
  143. transaction.commit();
  144. }
  145. //隐藏Fragment
  146. private void hideFragment(android.app.FragmentTransaction transaction) {
  147. if (homeFragment != null) {
  148. transaction.hide(homeFragment);
  149. }
  150. if (newsFragment != null) {
  151. transaction.hide(newsFragment);
  152. }
  153. if (friendFragment != null) {
  154. transaction.hide(friendFragment);
  155. }
  156. if (userFragment != null) {
  157. transaction.hide(userFragment);
  158. }
  159. }
  160. //重置链接样式
  161. private void restartBotton() {
  162. txt_home.setTextColor(Color.parseColor("#888888"));
  163. txt_news.setTextColor(Color.parseColor("#888888"));
  164. txt_friend.setTextColor(Color.parseColor("#888888"));
  165. txt_user.setTextColor(Color.parseColor("#888888"));
  166. }
  167. }

五、小结

方式1:基于ViewPager实现的内容:
优点:
1、界面可以滑动,美观,流畅。
缺点:
1、当界面里有一些需要用手势来实现的内容会起冲突,比如我们ListView里的侧滑删除。
2、由于采用的是ViewPager,所以页面内容实现代码会严重依赖于MainActivity,代码太过冗余,不便于后期维护。 

方式2:基于Fragment实现的内容:
优点:
1、Fragment文件单独存在,各自页面的内容各自去实现完成,有自己的生命周期,便于后期维护。
2、对于需要手势操作的一些内容不会起冲突。
缺点:
1、界面不可滑动,比较死板。

 

参考内容:

https://www.cnblogs.com/lichenwei/p/4444750.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/949515
推荐阅读
相关标签