• android ViewPager + Fragment + Tablayout 实现嵌套页面导航


    目录

    0、准备工作 

    (1)结构展示

     (2)底部tab栏准备

    1、创建布局  

     2、创建 VPfragment  

       (1) 构造 VPfragment 类

    (2)子页面布局 fragment_v_p.xml

    3、创建适配器 

    4、在 Activity_index 内整合

    第一步:先确认变量确认变量

    第二步: 获取控件

     第三步:准备fragment页面

    第四步:创建适配器,并设置监听 (页面绑定底部按钮)

    第五步:设置监听(底部按钮绑定页面)

    第六步:在onCreate方法内调用以上方法

    5、对“首页”字页面重新设置

    第一步:给子 fragment(“首页”)写一个适配器

    第二步:构造VPHomeFragment 类


    效果展示如下,完整代码在文章末尾 

    0、准备工作 

    (1)结构展示

    首先由一个主页面来展示三个字页面(“首页”,“推荐”,“我的”),这三个子页面由fragment来显示。

     (2)底部tab栏准备

    首页底部tab栏用 BottomNavigationView,我们可以创建一个menu文件来给tab栏按钮设置样式

    BottomNavigationView 控件引用该menu,来显示底边按钮

     bottom_nav_menu.xml

    1. <?xml version="1.0" encoding="utf-8"?>
    2. <menu xmlns:android="http://schemas.android.com/apk/res/android">
    3. <item android:id="@+id/menu_home"
    4. android:icon="@drawable/index"
    5. android:title="首页"/>
    6. <item android:id="@+id/menu_recommend"
    7. android:icon="@drawable/recommend"
    8. android:title="推荐"/>
    9. <item android:id="@+id/menu_mine"
    10. android:icon="@drawable/chicken"
    11. android:title="我的"/>
    12. </menu>

    icon:设置图标 

     

    1、创建布局  

        主页用 ViewPager + BottomNavigationView 来布局

    ViewPager控件作用:作为容器,显示子页面

    BottomNavigationView控件作用:制作底部按钮 

    activity_index.xml

    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="match_parent"
    5. xmlns:app="http://schemas.android.com/apk/res-auto"
    6. android:orientation="vertical">
    7. <androidx.viewpager.widget.ViewPager
    8. android:id="@+id/vp"
    9. android:layout_width="match_parent"
    10. android:layout_height="0dp"
    11. android:layout_weight="1"/>
    12. <com.google.android.material.bottomnavigation.BottomNavigationView
    13. android:id="@+id/bottom_nav_menu"
    14. android:layout_width="match_parent"
    15. android:layout_height="wrap_content"
    16. app:menu="@menu/bottom_nav_menu" />
    17. </LinearLayout>

     2、创建 VPfragment  

       (1) 构造 VPfragment 类

    我们可以把每个页面当成一个对象,我们要想创建这个对象就要使用fragment里的一些方法。所以要创建一个类并继续fragment,来构建子页面的布局

    因为这里是创建最简单的fragment类,所以我们之间选择编译器为我们提供的创建方法就行 

    主要实现三个方法:

    1. newInstance 接收参数,存放在bundle内
    2. onCreate  设置参数,从bundle内取参数
    3. onCreateView 构建页面

     因为我们要在子页面内放一张照片,所以我们要定义一个img参数来接收图片,并在onCreateView方法内进行设置 

        VPFrament

    1. package com.example.tabfragment.fragment;
    2. import android.os.Bundle;
    3. import androidx.fragment.app.Fragment;
    4. import android.view.LayoutInflater;
    5. import android.view.View;
    6. import android.view.ViewGroup;
    7. import android.widget.ImageView;
    8. import com.example.tabfragment.R;
    9. public class VPFragment extends Fragment {
    10. private static final String ARG_PARAM1 = "title";
    11. private static final String ARG_PARAM2 = "img";
    12. private String title;
    13. private int img;
    14. public static VPFragment newInstance(String title, int img) {
    15. VPFragment fragment = new VPFragment();
    16. Bundle args = new Bundle();
    17. args.putString(ARG_PARAM1, title);
    18. args.putInt(ARG_PARAM2,img);
    19. fragment.setArguments(args);
    20. return fragment;
    21. }
    22. @Override
    23. public void onCreate(Bundle savedInstanceState) {
    24. super.onCreate(savedInstanceState);
    25. if (getArguments() != null) {
    26. title = getArguments().getString(ARG_PARAM1);
    27. img = getArguments().getInt(ARG_PARAM2);
    28. }
    29. }
    30. @Override
    31. public View onCreateView(LayoutInflater inflater, ViewGroup container,
    32. Bundle savedInstanceState) {
    33. View view = inflater.inflate(R.layout.fragment_v_p, container, false);
    34. Bundle argument = getArguments();
    35. ImageView iv = view.findViewById(R.id.iv);
    36. iv.setImageResource(argument.getInt(ARG_PARAM2,R.drawable.ji1));
    37. return view;
    38. }
    39. }

    (2)子页面布局 fragment_v_p.xml

    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="match_parent"
    5. android:orientation="vertical">
    6. <ImageView
    7. android:id="@+id/iv"
    8. android:layout_width="wrap_content"
    9. android:layout_height="wrap_content"
    10. android:layout_gravity="center"/>
    11. </LinearLayout>

    3、创建适配器 

    为什么要创建适配器?

          适配器作用是把每个单独的fragment页面放在一起打包,传给ViewPager。只有ViewPager设置了适配器我们才能看见翻页的效果。

    所以我们要单独写一个类并继承 FragmentPagerAdapte

    Alt + Enter 主要实现 FragmentPagerAdapter 方法和构造方法

    1. MyFragmentStateVPAdapter  构造方法,用来接收参数
    2. getItem 根据position来获取页面
    3. getCount 获取页面的个数

        基本方法都实现完后,我们要定义一个变量来存储我们每个fragment子页面

    private List<Fragment> myFragmentList;

    定义变量 myFragmentList 后,我们需要在构造方法内赋值,并在getItem 和getCount 方法进行操作,具体看下面代码

    MyFragmentStateVPAdapter 

    1. package com.example.tabfragment.adapter;
    2. import androidx.annotation.NonNull;
    3. import androidx.fragment.app.Fragment;
    4. import androidx.fragment.app.FragmentManager;
    5. import androidx.fragment.app.FragmentPagerAdapter;
    6. import java.util.List;
    7. public class MyFragmentStateVPAdapter extends FragmentPagerAdapter {
    8. private List myFragmentList;
    9. public MyFragmentStateVPAdapter(@NonNull FragmentManager fm,List myFragmentList) {
    10. super(fm);
    11. this.myFragmentList = myFragmentList;
    12. }
    13. /**
    14. * 获取页面
    15. * @param position 页面的位置
    16. * @return 返回具体页面
    17. */
    18. @NonNull
    19. @Override
    20. public Fragment getItem(int position) {
    21. return myFragmentList == null ? null:myFragmentList.get(position);
    22. }
    23. /**
    24. * 获取adapter内存储的页面个数
    25. * @return
    26. */
    27. @Override
    28. public int getCount() {
    29. return myFragmentList == null ? 0 : myFragmentList.size();
    30. }
    31. }

    4、在 Activity_index 内整合

    第一步:先确认变量确认变量

    1. private ViewPager mViewPager; // 主页面来展示子页面 Viewpager
    2. private BottomNavigationView mBottomNavigationView; //主页面底部tab按钮
    3. private List<Fragment> mFragmentList; //存储fragment页面,用来作为构造adapter的参数
    4. private MyFragmentStateVPAdapter mStateVPAdapter;

    第二步: 获取控件

    1. private void initeView() {
    2. mViewPager = findViewById(R.id.vp);
    3. mBottomNavigationView = findViewById(R.id.bottom_nav_menu);
    4. }

     第三步:准备fragment页面

            因为我们要在ViewPage内滑动显示多个页面,所以我们要先把这几个页面创建好,存储到 mFragmentList,为下一步显示页面做准备

    1. private void initData() {
    2. mFragmentList = new ArrayList<>();
    3. VPFragment homeFragment = VPFragment.newInstance("首页", R.drawable.ji1);
    4. VPFragment recommendFragment = new VPFragment().newInstance("推荐",R.drawable.ji5);
    5. VPFragment mineFragment = new VPFragment().newInstance("我的",R.drawable.ji6);
    6. //添加页面
    7. mFragmentList.add(homeFragment);
    8. mFragmentList.add(recommendFragment);
    9. mFragmentList.add(mineFragment);
    10. }

    第四步:创建适配器,并设置监听 (页面绑定底部按钮)

            我们把上一步创建好的fragment页面,作为参数来构造适配器

    new MyFragmentStateVPAdapter(getSupportFragmentManager(), mFragmentList )

    第一个参数:getSupportFragmentManager() 这个大家记着就可以了,固定用法

    第二个参数: mFragmentList

         然后让mViewPager 设置该适配器,调用setAdapter() 方法

          接下来,让给mViewPager设置监听,调用addOnPageChangeListener(),目的是让mViewPager内的子页面与底部menu按钮相关联。

    1. private void setFListener() {
    2. mStateVPAdapter = new MyFragmentStateVPAdapter(getSupportFragmentManager(),mFragmentList);
    3. mViewPager.setAdapter(mStateVPAdapter);
    4. mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
    5. @Override
    6. public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
    7. @Override
    8. public void onPageSelected(int position) {onPagerSelected(position);}
    9. @Override
    10. public void onPageScrollStateChanged(int state) {}
    11. });
    12. }

      这里我把页面绑定底部按钮的代码提取出来了,方便大家查看。

      这里我们设置监听会返回翻页面的位置,然后在该页面下绑定对于的按钮

    mBottomNavigationView调用 setSelectedItemId方法,传入的参数是menu内每个item的id值 

    1. //给每个页面设置按钮,页面关联按钮,页面动,按钮动
    2. private void onPagerSelected(int position) {
    3. switch(position){
    4. case 0:
    5. mBottomNavigationView.setSelectedItemId(R.id.menu_home);
    6. break;
    7. case 1:
    8. mBottomNavigationView.setSelectedItemId(R.id.menu_recommend);
    9. break;
    10. case 2:
    11. mBottomNavigationView.setSelectedItemId(R.id.menu_mine);
    12. break;
    13. }
    14. }

    第五步:设置监听(底部按钮绑定页面)

    我们还要给底部按钮设置监听(按哪个按钮,跳到对于的页面)

    1. //反向处理,按钮设置点击事件,按钮关联页面
    2. private void setBListener() {
    3. mBottomNavigationView.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
    4. @Override
    5. public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    6. switch(item.getItemId()){
    7. case R.id.menu_home:
    8. mViewPager.setCurrentItem(0);
    9. break;
    10. case R.id.menu_recommend:
    11. mViewPager.setCurrentItem(1);
    12. break;
    13. case R.id.menu_mine:
    14. mViewPager.setCurrentItem(2);
    15. break;
    16. }
    17. return true;
    18. }
    19. });
    20. }

    第六步:在onCreate方法内调用以上方法

    调用以上方法并允许,结果如下 

    1. protected void onCreate(Bundle savedInstanceState) {
    2. super.onCreate(savedInstanceState);
    3. setContentView(R.layout.activity_index);
    4. initeView();
    5. initData();
    6. setFListener();
    7. setBListener();
    8. }

     

    5、对“首页”字页面重新设置

         在开头我们会发现,“首页”对应的子页面并不只是显示一个图片,而是tab栏+四个fragment,所以我们要重新准备一个fragment类和一个新的适配器。

    第一步:给子 fragment(“首页”)写一个适配器

            因为新的页面顶部到导航栏有标题,所以我们要重新再写一个适配器,实现getPageTitle()方法。

    getPageTitle方法用来返回每个页面的标题

    1. package com.example.tabfragment.adapter;
    2. import androidx.annotation.NonNull;
    3. import androidx.annotation.Nullable;
    4. import androidx.fragment.app.Fragment;
    5. import androidx.fragment.app.FragmentManager;
    6. import androidx.fragment.app.FragmentStatePagerAdapter;
    7. import java.util.List;
    8. public class MyFragmentStVpTitleAdapter extends FragmentStatePagerAdapter {
    9. private List mFragmentList;
    10. private List titleList;
    11. public MyFragmentStVpTitleAdapter(@NonNull FragmentManager fm,
    12. List mFragmentList,
    13. List titleList) {
    14. super(fm);
    15. this.mFragmentList = mFragmentList;
    16. this.titleList = titleList;
    17. }
    18. @NonNull
    19. @Override
    20. public Fragment getItem(int position) {
    21. return mFragmentList == null ? null:mFragmentList.get(position);
    22. }
    23. @Override
    24. public int getCount() {
    25. return mFragmentList==null? 0:mFragmentList.size();
    26. }
    27. @Nullable
    28. @Override
    29. public CharSequence getPageTitle(int position) {
    30. return titleList.get(position);
    31. }
    32. }

    第二步:构造VPHomeFragment 类

       构造VPHomeFragment 类 跟 构造 VPfragment 的步骤是一样的,唯一不同就VPHomeFragment 类中多了一个 onCreateView 方法。

        首先,VPHomeFragment 类要添加几个变量

    1. private ViewPager mViewPager;
    2. private TabLayout mTabLayout;
    3. private List<Fragment> mFragmentList;
    4. private List<String> titleList;
    5. private MyFragmentStVpTitleAdapter mStVPTitleAdapter;

    onCreateView 方法 

    1. @Override
    2. public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    3. super.onViewCreated(view, savedInstanceState);
    4. mViewPager = view.findViewById(R.id.home_vp);
    5. mTabLayout = view.findViewById(R.id.tab_layout);
    6. initData();
    7. //注意此处,getChild 嵌套
    8. mStVPTitleAdapter = new MyFragmentStVpTitleAdapter(getChildFragmentManager(),mFragmentList,titleList);
    9. mViewPager.setAdapter(mStVPTitleAdapter);
    10. mTabLayout.setupWithViewPager(mViewPager);//tab 适配页面
    11. }
    12. private void initData() {
    13. mFragmentList = new ArrayList<>();
    14. VPFragment vPfragment1 = VPFragment.newInstance("鸡",R.drawable.ji1);
    15. VPFragment vPfragment2 = VPFragment.newInstance("你",R.drawable.ji2);
    16. VPFragment vPfragment3 = VPFragment.newInstance("太",R.drawable.ji3);
    17. VPFragment vPfragment4 = VPFragment.newInstance("美",R.drawable.j4);
    18. mFragmentList.add(vPfragment1);
    19. mFragmentList.add(vPfragment2);
    20. mFragmentList.add(vPfragment3);
    21. mFragmentList.add(vPfragment4);
    22. titleList = new ArrayList<>();
    23. titleList.add("鸡");
    24. titleList.add("你");
    25. titleList.add("太");
    26. titleList.add("美");
    27. }

      布局  

           为了让首页实现下面效果,我们要对VPHomeFragment 类调用的xm文件重新布局

     fragment_v_p_home.xml

    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="match_parent"
    5. android:orientation="vertical">
    6. <com.google.android.material.tabs.TabLayout
    7. android:id="@+id/tab_layout"
    8. android:layout_width="match_parent"
    9. android:layout_height="wrap_content"/>
    10. <androidx.viewpager.widget.ViewPager
    11. android:id="@+id/home_vp"
    12. android:layout_width="match_parent"
    13. android:layout_height="match_parent"/>
    14. </LinearLayout>

    最后在Activity_index.java 内把 homeFragment类型修改为 VPHomeFragment

    VPHomeFragment homeFragment = VPHomeFragment.newInstance("我的",R.drawable.ji1);

    gitte获取代码:点击跳转 

  • 相关阅读:
    牛客网的Java面试笔记在GitHub开源了,什么水平?
    河北保定鱼米之乡重现 国稻种芯·中国水稻节:雄安新区稻田
    数据结构28TI
    线性表的应用 —— 静态链表
    《深入理解Java虚拟机》读书笔记--第十三章 线程安全与锁优化
    【C++心愿便利店】No.14---C++之探索list底层原理
    每天一道leetcode:剑指 Offer 68 - I. 二叉搜索树的最近公共祖先(适合初学者)
    C语言可变参数函数及其实现
    K8S 二进制部署
    java计算机毕业设计-中小学教育机构培训系统-源代码+系统+数据库+lw文档
  • 原文地址:https://blog.csdn.net/weixin_53564801/article/details/127777864