【问题标题】:Swipe between fragments with help of BottomNavigationBar借助 BottomNavigationBar 在片段之间滑动
【发布时间】:2021-03-17 14:17:43
【问题描述】:

bottom navigatiom bar 的帮助下,我很难找到一个很好的例子来说明如何在fragments 之间滑动。由于FragmentStatePagerAdapter 已被弃用,现在建议使用新的ViewPager2 而不是旧的ViewPager,我想在我的代码中使用ViewPager2FragmentStateAdapter。我找到了一个如何结合 BottomNavigationBar 和 ViewPager here 的示例,我想做类似的事情。我的代码与示例中的代码有许多相似之处,唯一的区别是我将代码放在片段而不是活动中。 Here is a picture of how my FrontendFragment display look like。我可以使用底部导航栏在视图之间切换,但我也希望能够在视图之间滑动。有人可以帮助我或至少指导我正确的方式吗?这是我的代码:

FragmentPagerAdapter 类:

public class FragmentPagerAdapter extends FragmentStateAdapter {

    private static final int mFragmentCount = 5;

    public FragmentPagerAdapter(@NonNull Fragment fragment) {
        super(fragment);
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        switch (position){

            case 0:
                return new HomeFragment();
            case 1:
                return new SearchFragment();
            case 2:
                return new AddFragment();
            case 3:
                return new MessageFragment();
            case 4:
                return new ProfileFragment();
        }
        return null;
    }

    @Override
    public int getItemCount() {
        return mFragmentCount;
    }
} 

前端片段类:

public class FrontendFragment extends Fragment implements BottomNavigationView.OnNavigationItemSelectedListener{

    private BottomNavigationView mBottomNavigationView;
    private ViewPager2 mViewPager2;
    private FragmentPagerAdapter mFragmentPagerAdapter;

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

        loadFragment(new HomeFragment());

        mBottomNavigationView = v.findViewById(R.id.bottomNavigationBar);
        mBottomNavigationView.setOnNavigationItemSelectedListener(this);


        return v;
    }

    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {

        Fragment selectedFragment = null;

        switch (item.getItemId()) {
            case R.id.home_icon:
                selectedFragment = new HomeFragment();
                break;
            case R.id.search_icon:
                selectedFragment = new SearchFragment();
                break;
            case R.id.add_icon:
                selectedFragment = new AddFragment();
                break;

            case R.id.message_icon:
                selectedFragment = new MessageFragment();
                break;

            case R.id.profile_icon:
                selectedFragment = new ProfileFragment();
                break;
        }
        
        return loadFragment(selectedFragment);
    }


    private boolean loadFragment(Fragment selectedFragment) {

        if(selectedFragment != null){

            MainActivity.sFm.beginTransaction().replace(R.id.relLayoutMiddle, selectedFragment).commit();
            return true;
        }
        return false;
    }
}

提前致谢!

【问题讨论】:

    标签: java android android-fragments android-viewpager2


    【解决方案1】:

    由于我已经在我的一个应用中使用带有 ViewPager2 的 BottomNav,我可以提供帮助。

    您的代码部分正确,这意味着您的 FragmentPagerAdapter 很好,但不是您的 FrontEndFragment

    看,FragmentPagerAdapter 必须设置为 ViewPager2

    //this here is the FrontEndFragment 
    mViewPager2.setAdapter(new FragmentPagerAdapter(this));
    

    那么,你根本不需要做FragmentTransaction,你只需要通过BottomNavigationBar改变ViewPager2的当前item位置为

    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    
        switch (item.getItemId()) {
            case R.id.home_icon:
                mViewPager2.setCurrentItem(0);
                break;
            case R.id.search_icon:
                mViewPager2.setCurrentItem(1);
                break;
            case R.id.add_icon:
                mViewPager2.setCurrentItem(2);
                break;
    
            case R.id.message_icon:
                mViewPager2.setCurrentItem(3);
                break;
    
            case R.id.profile_icon:
                mViewPager2.setCurrentItem(4);
                break;
        }
        
        return false;
    }
    

    这就是全部,除了FragmentPagerAdapter,您根本不需要处理Fragments。另外,不要忘记删除不需要的loadFragment(new HomeFragment());,也不要删除函数loadFragment()

    (可选),此外,如果您想禁用ViewPager2 的 Swipe Action 并希望仅基于 Selected BottomNav 项选择 Fragments,那么您可以将ViewPager2setUserInputEnabled() 属性设置为false.


    接下来,要根据ViewPager2的滑动将BottomNavigationBar的项目设置为选中,你要做的是,

    创建一个全局变量

    MenuItem previousMenuItem;
    

    然后,设置一个默认项(第一个)在 Activity 开始时选择 BottomNav 为

    mBottomNavigationView.getMenu().getItem(0).setChecked(true);
    

    最后,在ViewPager2 上设置一个OnPageSelected() 回调以将选定的菜单项更新为:

    mViewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            super.onPageScrolled(position, positionOffset, positionOffsetPixels);
        }
    
        @Override
        public void onPageSelected(int position) {
            super.onPageSelected(position);
            if (previousMenuItem != null) {
                previousMenuItem.setChecked(false);
            }
            else {
                mBottomNavigationView.getMenu().getItem(0).setChecked(false);
            }
            mBottomNavigationView.getMenu().getItem(position).setChecked(true);
            previousMenuItem = mBottomNavigationView.getMenu().getItem(position);
        }
    
        @Override
        public void onPageScrollStateChanged(int state) {
            super.onPageScrollStateChanged(state);
        }
    });
    

    您在这里所做的是将默认项目设置为previousMenuItem,然后滑动到另一个页面,取消选择previousMenuItem 并选择新的,这意味着根据 ViewPager 的当前更新底部导航物品。这是实现目标所需的完整代码。

    【讨论】:

    • 谢谢!我刚刚实现了你的代码,但是我在mViewPager2.setAdapter(new FragmentPagerAdapter()); 收到错误,因为我需要在FragmentPagerAdapter 中传递一个片段。我在那里通过什么?我还需要在正确设置适配器之前找到 viewpager2 id 吗?只是为了确保我是编码新手。再次感谢您的帮助!
    • @MohammedAbdu 是的,您必须将mViewPager2 初始化为mViewPager2 = v.findViewById(R.id.yourViewPagerID);,然后您必须设置它的适配器。而且,在FragmentPagerAdapter 中,您必须将Fragment 传递为mViewPager2.setAdapter(new FragmentPagerAdapter(this));。它会起作用的。
    • 非常感谢!我整天都在挣扎以找出该怎么做,现在你救了我! :) 它完全有效!
    • 最后一件事,因为我正在努力学习所有内容,这样我就不必再挣扎了。为什么我将this 作为片段传入? this 在这种情况下代表什么?如有任何不便,请见谅。
    • @MohammedAbdu this 始终取决于您发送它的范围。现在,您可能已经注意到FragmentStateAdapter 的构造函数需要一个片段,正如您的代码public FragmentPagerAdapter(@NonNull Fragment fragment) { 中定义的那样。它需要FrontEndFragment,当您传递this 时,您实际上将FrontEndFragment 的运行实例从自身传递为this。由于您在被覆盖的函数onCreateView() 中,而不是在另一个类的上下文中(如任何回调),所以它可以工作。否则,您必须将其指定为 this@FrontEndFragment
    【解决方案2】:

    如果您想在视图之间滑动,一个简单的解决方案是将所有视图存储在您的父视图中,但将除初始视图之外的所有视图布局设置为android:visibility="gone"。确保将初始视图布局设置为android:visibility="visible"。现在,在您单击按钮时,您将必须实现 onClick 以便它们相应地打开/关闭视图可见性。例如,按顺序存储视图并通过数组索引控制它们。但是您尝试做的整个事情通常不是一个好的设计模式在我看来

    您为什么不加载另一个 Activity onClick 而不是拥挤您的单个 Activity?这将导致加载时间问题。即使视图是不可见的,将所有这些都保存在一个地方也只是一件麻烦事。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-27
      • 1970-01-01
      • 1970-01-01
      • 2011-11-07
      相关资源
      最近更新 更多