【问题标题】:Android, combining bottom navigation with tabs (Activities vs. Fragments)Android,将底部导航与选项卡相结合(活动与片段)
【发布时间】:2018-12-28 21:13:51
【问题描述】:

地狱社区,

我是 Android 新手,我找不到该问题的好答案:

我想使用底部导航,一些元素也应该使用标签。

现在我的问题是最常见(最好)的实现方式是什么?

我对是否应该使用活动或片段进行此导航感到困惑。

仅对底部导航和选项卡使用片段是一种好的方式,还是将活动用于底部导航而仅对选项卡使用片段的最佳方式?

最好的问候

【问题讨论】:

  • 在同一屏幕上同时使用底部导航和标签可能会使用户感到困惑,如下所述:material.io/design/components/bottom-navigation.html#usage。在实施这种导航模式之前,问问自己是否可以改进导航工作流程以避免混合选项卡和底部导航。如果您发现这确实是您所需要的,我很乐意为您提供帮助!
  • @ThibaultSeisel 我以前也读过。我需要一种方法来浏览一些顶级目的地以及一些选项卡以在同一层次结构级别内的某些内容之间导航。我不确定导航抽屉和选项卡的组合是否会更好,但目前,我计划为底部导航设置 5 个目的地,但最终可能只有 4 个。材料指南建议使用带有 2-5 个元素的底部导航和仅具有 5 个以上元素的导航抽屉。

标签: android android-fragments bottomnavigationview


【解决方案1】:

最好的方法是同时使用Fragments。如果您为从底部导航可到达的每个屏幕使用Activity,则必须在每个屏幕中添加BottomNavigationView,并复制大量代码,以及调整这些活动之间的转换。

应将 Activity 视为应用程序的入口点:单击启动器中的应用程序图标时,会启动 Manifest 中定义的主要 Activity。 对于其他任何内容(部分 UI、部分导航流程...),您可以使用 Fragments。

这里有一个示例 Activity 和 Fragments 组织来解决您的问题:

MainActivity
     |--- TopLevelFragment1
     |--- TopLevelFragment2
     |           |--- TabFragment1
     |           |--- TabFragment2
     |           |--- TabFragment3
     |
     |--- TopLevelFragment3
     |--- TopLevelFragment4

正如您在上面的架构中看到的,一个 Activity 可以托管子片段,片段也可以有嵌套的片段(也称为“子片段”)。 TopLevelFragmentN 是在选择BottomNavigationView 中的项目时显示的片段。 TabFragmentN 是从TopLevelFragment2 中选择选项卡时显示的片段。

让我们深入了解实现。我没有测试过以下代码,这些只是提供指导。 以下是活动的示例代码:

main_activity.xml

<CoordinatorLayout android:id="@+id/coordinator_layout">
  <FrameLayout android:id="@+id/fragment_host"><!-- TopLevelFragments will be displayed here --></FrameLayout>
  <BottomNavigationView android:id="@+id/bottom_nav"/>
</CoordinatorLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {

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

        // Retrieve a reference to the BottomNavigationView and listen for click events.
        BottomNavigationView bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav);
        bottomNav.setOnNavigationItemSelectedListener(item -> {
            // Depending on the clicked item, change the displayed TopLevelFragment.
            switch(item.getItemId()) {
                case R.id.top_level_1:
                    showTopLevelFragment(new TopLevelFragment1());
                    return true;
                case R.id.top_level_2:
                    // Do the same with other TopLevelFragments
                    return true;
                default:
                    return false;
            }
        }

        // Show the first TopLevelFragment by default.
        showTopLevelFragment(new TopLevelFragment1());
    }

    private void showTopLevelFragment(Fragment fragment) {
        // Use the fragment manager to dynamically change the fragment displayed in the FrameLayout.
        getSupportFragmentManager().beginTransaction()
            .replace(R.id.fragment_host, fragment)
            .commit();
    }
}

请参考documentation了解如何在BottomNavigationView中定义项目。

现在,让我们关注包含标签的TopLevelFragment2。将TabLayoutViewPager 一起使用是一种常见的模式,这样您就可以通过向左或向右滑动从一个选项卡移动到另一个选项卡。

top_level_fragment_2.xml

<ConstraintLayout android:id="@+id/constraint_layout">    
    <AppBarLayout android:id="@+id/appbar_layout">
        <Toolbar android:id="@+id/toolbar"/>
        <TabLayout android:id="@+id/tab_layout"/>
    </AppBarLayout>
    <ViewPager android:id="@+id/tab_pager"/>
</ConstraintLayout>

TopLevelFragment2.java

public class TopLevelFragment2 extends Fragment {

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.top_level_fragment_2, container, false);
    }

    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        MyTabPagerAdapter tabPager = new MyTabPagerAdapter(getFragmentManager());

        ViewPager viewPager = getView().findViewById(R.id.tab_pager);
        viewPager.setAdapter(tabPager);

        // Display a tab for each Fragment displayed in ViewPager.
        TabLayout tabLayout = getView.findViewById(R.id.tab_layout);
        tabLayout.setupWithViewPager(viewPager);
    }

    static class MyTabPagerAdapter extends FragmentPagerAdapter {
        MyTabPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public int getCount() {
            return 3; // One for each tab, 3 in our example.
        }

        @Override
        public Fragment getItem(int position) {
            switch(position) {
                case 0:
                    return new TabFragment1();
                case 1:
                    // Return a new instance of the fragment associated with the tab at position 1
                default:
                    throw new IllegalArgumentException();
            }
        }
    }
}

完成这些步骤后,您所要做的就是为其他片段编写代码。

【讨论】:

  • 感谢您的回答。尝试像这样实现它,但是当我尝试在约束布局中使用 AppBarLayout 时,我确实收到错误消息:此检查突出显示 Android 资源文件和 AndroidManifest.xml 中不允许的 XML 标记。有什么想法吗?
  • 你说得对,AppBarLayout 只能用作CoordinatorLayout 的直接子代。我建议用LinearLayout 替换它,因为它的行为与AppBarLayout 相同(减去滚动效果),以​​便您可以测试bottomnav + tabs 的实现。
  • 这真的很有帮助。我已经在实现这个设计模式了。就我而言,我还需要一个 DrawerLayout。你能告诉我如何也包括 DrawerLayout 吗?入门代码或示例链接会很有帮助。谢谢。
  • 另外,我可以看到我的片段中的选项卡已加载。但是,这些片段显示为完全空白。即使我在这两个片段中都添加了 TextViews,但这些片段并没有显示出来。有什么线索吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多