Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换

2024-06-04 2366阅读

前言

通过几次的踩雷和摸索,完成了以上的操作,本教程写的详细全面,包教包会,对新手有好,看了不会的联系我,我倒立洗头给你看。

Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换 第1张

1.需要了解的一些知识

所需控件:

fragment

作为Android中最常用的控件,它有自己的声明周期,可以粗略地等比为能够分屏的activity,但是和activity有区别,fragment有自己的生命周期和接收、处理用户的事件。Fragment必须是依存与Activity而存在的。所以他们可以有自己的xml文件(布局文件)和class文件(处理逻辑的java类文件)。

Viewpager

ViewPager是可以实现多个界面的左右滑动的控件。ViewPager最典型的应用场景主要包 括引导页导航,轮转广告和页面菜单。其中有两个ViewPager适配器需要使用

  • FragmentStatePagerAdapter:

    它是 PagerAdapter 的子类,用于处理多个碎片,并支持动态加载和销毁碎片来节省内存。适用于需要处理大量页面、支持动态刷新以及动态添加或删除页面的场景。例如图片浏览器、新闻阅读器等。

  • FragmentPagerAdapter:

    它也 是 PagerAdapter 的子类,与 FragmentStatePagerAdapter 类似,但有一些不同之处。与 FragmentStatePagerAdapter 相比,FragmentPagerAdapter 更适用于静态、数量有限的页面集合,并提供更好的滑动性能和用户体验,因为它不会销毁已经创建的碎片实例。

    我们接下来要使用的是FragmentPagerAdapter。

    java语法结构

    List

    List 是 Java 中的泛型类,一种动态数组,用于表示一个列表,可以存储任意类型的元素。在使用 List 时,需要在尖括号中指定具体的类型参数。可以实现增,删,替换等操作。举个例子

     List stringList = new ArrayList();
     stringList.add("Hello");
     stringList.add("World");
     ​
     List integerList = new ArrayList();
     integerList.add(1);
     integerList.add(2);
     ​
     for (String str : stringList) {
         System.out.println(str);
     }
     ​
     for (int num : integerList) {
         System.out.println(num);
     }

      ​首先,创建了一个 List 类型的列表 stringList,并向其中添加两个字符串元素 "Hello" 和 "World"。

    接下来,创建了一个 List 类型的列表 integerList,并向其中添加两个整数元素 1 和 2。

    然后,通过使用增强型 for 循环,分别对 stringList 和 integerList 进行迭代遍历,将列表中的元素逐个取出,并分别打印输出。

    在第一个循环中,每次迭代将当前的字符串元素赋值给变量 str,然后将其输出。因此,在循环的第一次迭代中,会输出 "Hello",在第二次迭代中,会输出 "World"。

    在第二个循环中,每次迭代将当前的整数元素赋值给变量 num,然后将其输出。因此,在循环的第一次迭代中,会输出 1,第二次迭代中,会输出 2。

    所以最终的输出结果是:

     Hello
     World
     1
     2

    2.准备工作

    1.导入所需包

    在build.gradle文件中引入implementation 'com.google.android.material:material:1.9.0'

    Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换 第2张

    当导入进去后,可能会有版本不一样的情况,如果报黄,点击alt+enter键,会出现修改版本的选项。当引入完以后,就可以点击sync进行数据操作同步。如果已经有了这个包就可以不用管他了。

    2.创建三个fragment

    Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换 第3张

    根据我上述截图来操作,创建三个名字分别为homeFragment,moreFragment,userFragment。其对应布局文件名字为fragment_home,fragment_more,fragment_user。

    创建好后三个fragment的class里面的暂时先不用管

    3.创建menu

    BottomNavigationView 可以来创建底部导航栏,而菜单项组合menu就在其中。

    先在res文件夹中创建一个menu文件夹

    Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换 第4张

    然后创建一个名为menu的xml文件,将下列代码写进文件中:

     
     
     ​
         
     ​
         
     ​
         
     ​
     
     
    

    其中@drawable/user是drawable下的user.png,一张图片,由 android:icon引用。同理"@string/user"是 res/values/strings.xml文件里的用户代码,这样,底部导航栏菜单项的标题就会显示为 "用户"。这里推荐使用阿里矢量图标库。drawable文件是用于存放图片的,把图复制粘贴进去就行。其中名字不能为中文等字符,不然会报错。

     Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换 第5张

    4.编写ViewPagerAdapter继承FragmentPagerAdapter

    完成底部导航栏的切换我们需要FragmentPagerAdapter的帮助,所以创建并编写ViewPagerAdapter类(这是我取的名字,想取什么名字都行)继承FragmentPagerAdapter。

    代码如下:

    package com.example.bnvone.Adapter;
     ​
     import androidx.annotation.NonNull;
     import androidx.fragment.app.Fragment;
     import androidx.fragment.app.FragmentManager;
     import androidx.fragment.app.FragmentPagerAdapter;
     ​
     import java.util.List;
     ​
     public class ViewPagerAdapter extends FragmentPagerAdapter {
         private List mfragmentList;
         public ViewPagerAdapter(@NonNull FragmentManager fm,List fragmentList) {
             super(fm);//调用父类构造函数,传递FragmentManager 参数
                       //用于确保适配器类内部具有有效的 FragmentManager 实例,从而顺利完成片段管理和展示的任务
             this.mfragmentList = fragmentList;
     ​
         }//设置 ViewPager 的适配器。
     ​
     ​
         @NonNull
         @Override
         public Fragment getItem(int position) {
             return  mfragmentList == null ? null: mfragmentList.get(position);
         }// mfragmentList == null ? null 判断mfragmentList是否为空,如果不为null,执行:后面的代码。
          //mfragmentList.get(position)获得第position个的fragment对象返回
     ​
         @Override
         public int getCount() {
             return  mfragmentList == null ? null: mfragmentList.size();
             // 返回片段对象的数量,即mfragmentList列表中的元素个数
         }
     }
     
     ​

    这个适配器的作用是将 Fragment 列表与 ViewPager 关联起来,以便在 ViewPager 中展示相应的内容。通过重写 getItem 和 getCount 方法,适配器可以根据位置返回对应的 Fragment 对象,并在 ViewPager 中正确显示。其中重写的方法我们会在MainActivity中调用。

    前期准备的差不多了,可以开始实现了。

    3.实现底部导航栏同步切换操作

    1.创建MainActivity

     
     
     ​
         
     ​
     ​
         
     ​
     ​
     ​
     
     ​

    使用的线性布局,也可以使用其他的。出现vp : No speakable text present问题不大,可以运行。得到的样子是这样的

     Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换 第6张

    2.编写MainActivity

     package com.example.bnvone;
     ​
     import androidx.annotation.NonNull;
     import androidx.appcompat.app.AppCompatActivity;
     import androidx.fragment.app.Fragment;
     import androidx.viewpager.widget.ViewPager;
     ​
     import android.annotation.SuppressLint;
     import android.os.Bundle;
     import android.view.MenuItem;
     ​
     import com.example.bnvone.Adapter.ViewPagerAdapter;
     import com.example.bnvone.Fragment.homeFragment;
     import com.example.bnvone.Fragment.moreFragment;
     import com.example.bnvone.Fragment.userFragment;
     ​
     import com.google.android.material.bottomnavigation.BottomNavigationView;
     ​
     import java.util.ArrayList;
     import java.util.List;
     ​
     public class MainActivity extends AppCompatActivity {
         private BottomNavigationView navigationView;
         private ViewPager viewPager;
     ​
     ​
         @Override
         protected void onCreate(Bundle savedInstanceState) {
     ​
             super.onCreate(savedInstanceState);
             setContentView(R.layout.activity_main);
     ​
             navigationView = findViewById(R.id.nav_bottom);
             viewPager = findViewById(R.id.vp);
     ​
             homeFragment homeFragment= new homeFragment();
     ​
             List fragments = new ArrayList();
             fragments.add(new homeFragment()); //新建一个homeFragment对象将这个对象加入到数组fragments中
             fragments.add(new moreFragment());
             fragments.add(new userFragment());
     ​
             ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager(),fragments);
             //创建对象并通过构造函数初始化,该适配器可以知道要显示哪些片段。
             viewPager.setAdapter(viewPagerAdapter);
             //将前面创建的 viewPagerAdapter 适配器设置给 viewPager 视图组件,以便在 ViewPager 中显示相应的页面。
             //底部导航栏监听事件
             navigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
                 @SuppressLint("NonConstantResourceId")
                 @Override
                 public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                 //根据菜单ID显示页面
                     switch (item.getItemId()) {//监听事件中,点击菜单立马执行item.getItemId()方法
                         //item.getItemId() 方法用于获取选中的 MenuItem 的唯一标识符(ID)
                         case R.id.item_home://R.id.xxx是整数类型。
                             viewPager.setCurrentItem(0);
                             // 将 ViewPager 的当前页面显示成索引为 0 的页面
                             return true;
                         case R.id.item_more:
                             viewPager.setCurrentItem(1);
                             return true;
                         case R.id.item_user:
                             viewPager.setCurrentItem(2);
                             return true;
                     }
                     return false;
                 }
     ​
             });
     ​
             // 添加页面切换的监听器,根据页面切换实现菜单切换
         viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
             @Override
             public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
     ​
             }
     ​
             @Override
             public void onPageSelected(int position) {
             switch (position){  // 根据页面位置更新导航栏的选中状态
                 case 0:
                     navigationView.setSelectedItemId(R.id.item_home);
                     //将导航栏中的选中项设置为 R.id.item_home
                     break;
                 case 1:
                     navigationView.setSelectedItemId(R.id.item_more);
                     break;
                 case 2:
                     navigationView.setSelectedItemId(R.id.item_user);
                     break;
             }
          }
     ​
             @Override
             public void onPageScrollStateChanged(int state) {}
         });//通过使用页面切换监听器,
             // 我们可以根据页面切换的情况来更改导航栏的选中状态,
             // 从而实现页面切换时导航栏菜单的同步切换效果。
     ​
         }
     }
     ​
     
    

    实现了底部导航栏与 ViewPager 的联动效果。底部导航栏通过监听选中项的改变,然后根据选中项对应的页面索引,调用 ViewPager 的 setCurrentItem 方法来切换到相应的页面。同时,ViewPager 添加了页面切换的监听器,通过监听页面的切换事件,更新底部导航栏的选中状态,以实现同步切换效果。

    完成以下操作就可以实现同步切换了。

    补充

    我的fragment代码:

     
     ​
         
     ​
             
     ​
         
     
     
    

    本次操作所需要所有文件:

     Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换 第7张

    效果如下:

    Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换 第8张

    是不是很简单,有手就行

    Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换 第9张

    会了的话就给个推荐之类的吧,各位兄弟们

    Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换 第10张

    ----------------2023年11月23日修改----------------

    拓展使用

    随着软件的不断成熟,导航栏的样式也变得越来越多,各大APP顶部导航栏流行使用字体当做顶部导航栏,并在选中后实现放大等样式改变的效果。

    Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换 第11张Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换 第12张Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换 第13张

    我们来简单实现一下这种效果:

    创建viewpagerActivity

    创建一个新的activity,命名viewpagerActivity;

    XML文件

    他的布局代码如下:

    
        
            
            
        
        
        
    

    是这种效果:

    Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换 第14张

    再按上文创建两个fragment,一个oneFragment,一个twoFragment;

    java文件
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.fragment.app.Fragment;
    import androidx.viewpager.widget.ViewPager;
    import android.graphics.Color;
    import android.os.Bundle;
    import android.util.TypedValue;
    import android.view.View;
    import android.widget.TextView;
    import android.widget.Toast;
    import java.util.ArrayList;
    import java.util.List;
    public class viewpagerActivity extends AppCompatActivity {
        TextView textView1;
        TextView textView2;
        ViewPager viewPager;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_viewpager);
            textView1 = findViewById(R.id.textView1);
            textView2 = findViewById(R.id.textView2);
            viewPager = findViewById(R.id.viewPager);
            List fragments = new ArrayList();
            fragments.add(new oneFragment());
            fragments.add(new twoFragment());
            ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager(),fragments);
            viewPager.setAdapter(viewPagerAdapter);
            textView1.animate().scaleX(1.5f).scaleY(1.5f).setDuration(0).withEndAction(new Runnable() {
                @Override
                public void run() {
                }
            }).start();
            textView1.setTextColor(Color.BLACK);
            textView1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    textView1.setTextColor(Color.BLACK);
                    viewPager.setCurrentItem(0);
                }
            });
            textView2.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    viewPager.setCurrentItem(1);
                }
            });
            viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                }
                @Override
                public void onPageSelected(int position) {
                    switch (position){
                        case 0:
                            textView1.animate().scaleX(1.5f).scaleY(1.5f).setDuration(100).withEndAction(new Runnable() {
                                @Override
                                public void run() {
                                }
                            }).start();
                            textView2.animate().scaleX(1f).scaleY(1f).setDuration(100).withEndAction(new Runnable() {
                                @Override
                                public void run() {
                                }
                            }).start();
                            textView1.setTextColor(Color.BLACK);
                            textView2.setTextColor(Color.GRAY);
                            break;
                        case 1:
                            textView2.animate().scaleX(1.5f).scaleY(1.5f).setDuration(100).withEndAction(new Runnable() {
                                @Override
                                public void run() {
                                }
                            }).start();
                            textView1.animate().scaleX(1f).scaleY(1f).setDuration(100).withEndAction(new Runnable() {
                                @Override
                                public void run() {
                                }
                            }).start();
                            textView2.setTextColor(Color.BLACK);
                            textView1.setTextColor(Color.GRAY);
                            break;
                    }
                }
                @Override
                public void onPageScrollStateChanged(int state) {
                }
            });
        }
        
    }

    完成后的效果如下:

    Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换 第15张


    免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

    目录[+]