草庐IT

Android ViewPager2 + Fragment + BottomNavigationView 联动

AskaJohnny 2023-04-16 原文

Android ViewPager2 + Fragment + BottomNavigationView 联动

本篇主要介绍一下 ViewPager2 + Fragment + BottomNavigationView , 上篇中把ViewPager2和Fragment 联动起来了, 本篇主要把 BottomNavigationView集成进去

概述

BottomNavigationView 是一个底部导航控件, 现在要实现的效果就是 滑动ViewPager2 中的Fragment 并且底部BottomNavigationView 菜单部分跟着联动 同理反过来 点击BottomNavigationView 的时候 ViewPager2中的Fragment 也对应滑动, 下面来看看如何实现的吧

实现思路

1.Activity 布局文件中引入 ViewPager2 控件
2.编写menu文件 提供给BottomNavigationView 用于展示
3.Activity 布局文件中引入BottomNavigationView 控件
4.编写 Fragment 用于填充到ViewPager2中
5.编写Adapter 实现 FragmentStateAdapter
6.BottomNavigationView添加 setOnItemSelectedListener 联动ViewPager2
7.ViewPager2 添加 registerOnPageChangeCallback 联动 BottomNavigationView

代码实现

下面就来按照上面的思路一步步实现代码啦!

1.Activity 布局文件中引入 ViewPager2 控件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ViewPager2BottomActivity">


    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewpager2bottom"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/bootomnav2"
        />


</androidx.constraintlayout.widget.ConstraintLayout>

2.编写menu文件 提供给BottomNavigationView 用于展示

图标icon 自己配置吧

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:title="首页"
        android:id="@+id/home_item"
        android:icon="@drawable/ic_baseline_home_24"
        />

    <item
        android:title="类型"
        android:id="@+id/type_item"
        android:icon="@drawable/ic_baseline_merge_type_24"
        />

    <item
        android:title="添加"
        android:id="@+id/add_item"
        android:icon="@drawable/ic_baseline_add_24"
        />

    <item
        android:title="设置"
        android:id="@+id/setting_item"
        android:icon="@drawable/ic_baseline_settings_24"
        />
</menu>

3.Activity 布局文件中引入BottomNavigationView 控件

package com.johnny.slzzing;

import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import org.w3c.dom.Text;

/**
 * A simple {@link Fragment} subclass.
 * Use the {@link Bottom2Fragment#newInstance} factory method to
 * create an instance of this fragment.
 */
public class Bottom2Fragment extends Fragment {

    // TODO: Rename parameter arguments, choose names that match
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";

    // TODO: Rename and change types of parameters
    private String mParam1;
    private String mParam2;

    public Bottom2Fragment() {
        // Required empty public constructor
    }

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @param param1 Parameter 1.
     * @param param2 Parameter 2.
     * @return A new instance of fragment Bottom2Fragment.
     */
    // TODO: Rename and change types and number of parameters
    public static Bottom2Fragment newInstance(String param1, String param2) {
        Bottom2Fragment fragment = new Bottom2Fragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_bottom2, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        TextView textView = view.findViewById(R.id.textview2);
        //把动态传入的参数设置到 textView上
        textView.setText(mParam1);
    }
}

fragment_bottom2.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ViewPager2BottomActivity">


    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewpager2bottom"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/bootomnav2"
        />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bootomnav2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@id/viewpager2bottom"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:menu="@menu/bottom_item_menu"                                        
        app:labelVisibilityMode="labeled" 
        />
<!-- 这个要设置 app:labelVisibilityMode="labeled"  才能显示图标文字 因为我这里超过了3个-->        
</androidx.constraintlayout.widget.ConstraintLayout>

4.编写 Fragment 用于填充到ViewPager2中

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".Bottom2Fragment">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:id="@+id/textview2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/hello_blank_fragment"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:gravity="center"
        android:textSize="25sp"
        android:textStyle="bold"
        android:textColor="@color/black"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

5.编写Adapter 实现 FragmentStateAdapter

上篇已经说过了 直接继承 FragmentStateAdapter

class MyViewPager2BottomAdapter extends FragmentStateAdapter {

    List<Fragment> fragmentList;
    public MyViewPager2BottomAdapter(@NonNull FragmentActivity fragmentActivity, List<Fragment> list) {
        super(fragmentActivity);
        this.fragmentList = list;
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        return fragmentList.get(position);
    }

    @Override
    public int getItemCount() {
        return fragmentList.size();
    }
}

6.BottomNavigationView添加 setOnItemSelectedListener 联动ViewPager2

bottomNavigationView.setOnItemSelectedListener核心方法

Acitivity 中实现如下代码:

  protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_view_pager2_bottom);

        viewPager2 = findViewById(R.id.viewpager2bottom);
        bottomNavigationView = findViewById(R.id.bootomnav2);
        MyViewPager2BottomAdapter myViewPager2BottomAdapter =
                new MyViewPager2BottomAdapter(this,initFragmentList());
        viewPager2.setAdapter(myViewPager2BottomAdapter);
        //重点 设置 bottomNavigationView 的item 的点击事件 设置viewPager2的联动
        bottomNavigationView.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                int itemId = item.getItemId();
                switch (itemId){
                    case R.id.home_item:
                        viewPager2.setCurrentItem(0);
                        break;
                    case R.id.type_item:
                        viewPager2.setCurrentItem(1);
                        break;
                    case R.id.add_item:
                        viewPager2.setCurrentItem(2);
                        break;
                    case R.id.setting_item:
                        viewPager2.setCurrentItem(3);
                        break;
                }
                return true;
            }
        });

    }

7.ViewPager2 添加 registerOnPageChangeCallback 联动 BottomNavigationView

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_view_pager2_bottom);

    viewPager2 = findViewById(R.id.viewpager2bottom);
    bottomNavigationView = findViewById(R.id.bootomnav2);
    MyViewPager2BottomAdapter myViewPager2BottomAdapter =
            new MyViewPager2BottomAdapter(this,initFragmentList());
    viewPager2.setAdapter(myViewPager2BottomAdapter);

    bottomNavigationView.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            int itemId = item.getItemId();
            switch (itemId){
                case R.id.home_item:
                    viewPager2.setCurrentItem(0);
                    break;
                case R.id.type_item:
                    viewPager2.setCurrentItem(1);
                    break;
                case R.id.add_item:
                    viewPager2.setCurrentItem(2);
                    break;
                case R.id.setting_item:
                    viewPager2.setCurrentItem(3);
                    break;
            }
            return true;
        }
    });
     //重点 实现滑动的时候 联动 bottomNavigationView的selectedItem
    viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
        @Override
        public void onPageSelected(int position) {
            super.onPageSelected(position);
            switch (position){
                case 0:
                    bottomNavigationView.setSelectedItemId(R.id.home_item);
                    break;
                case 1:
                    bottomNavigationView.setSelectedItemId(R.id.type_item);
                    break;
                case 2:
                    bottomNavigationView.setSelectedItemId(R.id.add_item);
                    break;
                case 3:
                    bottomNavigationView.setSelectedItemId(R.id.setting_item);
                    break;
            }
        }
    });

}

总结

本篇主要介绍了 如何把ViewPager2 + Fragment + BottomNavigationView 集成起来并且实现ViewPager2和BottomNavigationView的双向联动

ViewPager和ViewPager2 一些区别:

  • ViewPager 的 Adapter 继承 FragmentStatePagerAdapter 而 ViewPager2 的Adapter 继承 FragmentStateAdapter
  • ViewPager 滑动监听是 viewPager.addOnPageChangeListener方法 而ViewPager2 滑动监听是 registerOnPageChangeCallback 方法

欢迎大家访问 个人博客 Johnny小屋
欢迎关注个人公众号

有关Android ViewPager2 + Fragment + BottomNavigationView 联动的更多相关文章

  1. uni-app制作一个左侧导航scroll-view组件,并和页面主体展示联动 - 2

    先给大家看看最终效果首先我们来定义数据data(){ return{ lsit:[ 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic118.nipic.com%2Ffile%2F20161216%2F24271963_122609717000_2.jpg&refer=http%3A%2F%2Fpic118.nipic.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1656923017&t=183ece148b13b64e9dd503afd1b15c91'

  2. ruby-on-rails - Rails 4.0 expire_fragment/缓存过期不起作用 - 2

    我一直在尝试使用Rails的缓存功能,但我无法使某些缓存片段过期,尽管它们似乎已过期。使用Rails教程站点中指出的“俄罗斯娃娃缓存”,我正在使用此配置我在release_controller.rbController中使外部缓存过期,我在其中使用expire_fragment("all_available_releases")使片段过期。我在更新、删除或添加条目的Controller的每个方法中都使用它。这是WEBrick的日志,尽管过期片段已在其中注册,但5行后过期片段被读取并使用,而这是不应该的。这个例子是在destroy调用之后。ProcessingbyReleasesCont

  3. ruby-on-rails - 如何从 Rails Observer/Model 调用 expire_fragment? - 2

    我几乎什么都试过了,但似乎无法使用来自模型的expire_fragment?我知道你不应该这样做非MVC,但肯定有很多方法可以做到。我在lib/cache_helper.rb中用我所有的过期助手创建了一个模块,在每个中只是一堆expire_fragment调用。我有我所有的/app/sweepers下的缓存清扫器设置,并有一个“includeCacheHelper”在我的应用程序Controller中,因此在通过Controller调用时应用程序工作正常。然后事情是我有一些外部守护进程,尤其是一些循环的cron任务调用一个调用特定任务的rake任务方法。此方法进行一些处理并将条目输入到

  4. javascript - Three.js: Resize rendering canvas (GPU hungry fragment shader) - 2

    我正在使用three.js运行资源匮乏的片段着色器。我已将渲染大小设置为800*600,以保持着色器即使在低端卡上也能流畅运行。我正在这样设置我的渲染Canvas:varcanvas1=document.getElementById('canvas1');renderer=newTHREE.WebGLRenderer(canvas1);renderer.setSize(800,600);renderer.autoClear=false;document.body.appendChild(renderer.domElement);在body元素上我有然后我在cssheader中做widt

  5. java - BottomNavigationView 后退按钮无法正常工作 - 2

    当按下后退按钮时,我的fragment正在更改为主页,但底部图标没有改变。我在这里发布了我的所有代码。如果我从底部导航View项目中选择了两个以上的导航按钮,那么当我按下后退按钮时,它将重定向到最后选择的按钮项目。但现在发生的事情是,假设我在最后一个项目上说“通知”[如您在屏幕截图中所见],现在当我按下后退按钮时,它会直接带我到“主页”按钮,但是我想要的是它应该首先带我到“搜索”按钮项目然后到“主页”而不是直接到“主页”。我怎样才能做到这一点?这是布局:这是Activity:publicclassMainActivityextendsAppCompatActivity{privates

  6. java - 单击后退按钮更改 BottomNavigationView 图标 - 2

    在我的布局底部,我有一个包含三个fragment的BottomNavigationView。如果我单击后退按钮,fragment会切换,但不会切换底部图标。我该如何解决?addToBackStack()有效。也许您对代码的美化有一些建议。在Activity或fragment中使用fragment标签是一种好的做法吗?publicclassMainActivityextendsAppCompatActivity{privateFragmentManagermFragmentManager;privateBottomNavigationViewmBottomNavigationView;p

  7. java - 如何通过单击 fragment 内的线性布局从 fragment 类开始新 Activity ?下面是我的代码,但这不起作用 - 2

    当我点击fragment中的线性布局时,它不会给出任何错误,但不会开始新的Activity。我的代码有什么错误吗?请有人帮助我。我的项目的这个fragmentxml文件代码。Fragment_one.xml我的项目的这段java类代码。FragmentOne.javainfo.androidhive.listviewfeed;importandroid.app.Fragment;importandroid.content.Intent;importandroid.os.Build;importandroid.os.Bundle;importandroid.view.LayoutInfl

  8. java - NullPointerException 在 textview 中使用 fragment - 2

    我在tv.setMovementMethod(newScrollingMovementMethod());上遇到了NullPointerException但我完全不知道为什么!我已经在XML文件中声明了textView并在onCreateView中对其进行了初始化。任何帮助,将不胜感激。这里是java代码的相关部分:publicclassTestConnectionextendsFragment{publicTestConnection(){}JSONParserjParser=newJSONParser();//buttonpressedtogettheitemsButtongetA

  9. Android:无法启动 Activity ComponentInfo{/com.}:android.view.InflateException:二进制 XML 文件行错误膨胀类 fragment - 2

    我使用GoogleMapsAndroidv1API创建了我的应用程序的第一个版本。但是现在当我发布第二个版本的应用程序时,谷歌地图停止工作。我认为这是因为它已被弃用。所以现在我正在尝试创建示例Android应用程序以使用链接使用Googlemaphttps://developers.google.com/maps/documentation/android/start#getting_the_google_maps_android_api_v2但是我遇到了强制关闭错误FATALEXCEPTION:mainjava.lang.RuntimeException:Unabletostarta

  10. java - 使用 ViewPager 在 Fragment 中创建 Listview - 2

    我正在尝试开发一个时间线,就像下面的facebook一样。你看,我有一个ViewPager可以在“fragment”(如提要、个人资料、关于等)之间导航用户。我有“main.xml”,它上面只有viewpager;我还有fragmenta.xml、fragmentb.xml、fragmentc.xml。让我们检查一下fragmenta.xml,我把它放在里面;并制作了singlerow.xml来将这些框创建成这样的时间线;我让它只使用一个静态框。但是当我尝试运行这个结构时,我在Debug模式下遇到错误“找不到来源编辑源查找路径”在我尝试像这样将我的适配器和其他关于listview的东西

随机推荐