我应该为片段中的选项卡使用嵌套片段吗?
Should I use a nested fragment for tabs in a fragment?
我有一个 Main Activity,它使用 AHBottomNavigationView 作为屏幕底部的菜单。单击不同的菜单项时,它会创建一个与该菜单项对应的新片段,其逻辑如下(为简化此问题而使用的精简 switch 语句):
fragmentManager.beginTransaction().replace(R.id.content_id, New TheFragmentForTheTabClicked).commit();
其中 content_id
是 Main Activity 的 ConstraintLayout 的 ID。
在我的第一个导航菜单项的片段中,还有两个选项卡(使用 TabLayout),它们用另一个片段替换了屏幕 space。这是通过设置在 ViewPager 上的 FragmentPagerAdapter 完成的,因此点击每个选项卡都会更改子片段。所以此时,有一个片段嵌套在一个class的片段中。它通常是这样的:
Main Activity
|
+-- Fragment 1 (selected from AHBottomNavigationView)
| |
| +-- Sub-Fragment 1 (selected by clicking the first tab in Fragment 1)
| |
| +-- Sub-Fragment 2 (selected by clicking the second tab in Fragment 1)
|
+-- Fragment 2 (selected from AHBottomNavigationView)
|
+-- Fragment 3 (selected from AHBottomNavigationView)
|
+-- Fragment 4 (selected from AHBottomNavigationView)
所以我的问题是:
我这样做的方式是否正确,如果不正确,更好的方法是什么?
另外,我发现当我第一次选择 Fragment 1 时,两个选项卡之间的滑动和点击工作正常,但是如果我点击不同的底部导航菜单项(即 Fragment 3)然后返回,我得到以下 2 个问题:
- 未显示任一子片段中的内容
- 在两个选项卡之间滑动不再有效。我必须完全拉过屏幕,而不是一个移动到不同选项卡的动作,因为指示器在两个选项卡之间 "stuck" 中途。
如果我可以提供更多信息,请告诉我,我会的。
Fragment1.java:
package com.mypackage.mypackage;
import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* A simple {@link Fragment} subclass.
*/
public class Fragment1 extends Fragment {
private FragmentActivity mContext;
public Fragment1() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_1, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
// Find the view pager that will allow the user to swipe between fragments
ViewPager viewPager = (ViewPager) getView().findViewById(R.id.viewpager);
// Create an adapter that knows which fragment should be shown on each page
// using getFragmentManager() will work too
Fragment1PagerAdapter adapter = new Fragment1PagerAdapter(mContext.getSupportFragmentManager(), mContext);
// Set the adapter onto the view pager
viewPager.setAdapter(adapter);
TabLayout tabLayout = (TabLayout) getView().findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
}
/**
* Override to set context. This context is used for getSupportFragmentManager in onCreateView
* @param activity
*/
@Override
public void onAttach(Activity activity) {
mContext=(FragmentActivity) activity;
super.onAttach(activity);
}
}
fragment_1.xml
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="@+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabBackground="@color/fragment1TabBackground"
app:tabIndicatorColor="@color/fragment1TabIndicatorColor"/>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"/>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
Fragment1PagerAdapter.java
package com.mypackage.mypackage;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.content.Context;
public class Fragment1PagerAdapter extends FragmentPagerAdapter {
private Context context;
public Fragment1PagerAdapter(FragmentManager fm, Context mContext){
super(fm);
context = mContext;
}
@Override
public Fragment getItem(int position){
if (position == 0){
return new SubFragment1();
}
else{
return new SubFragment2();
}
}
@Override
public int getCount() {return 2;}
@Override
public CharSequence getPageTitle(int position) {
switch(position){
case 0:
return context.getResources().getString(R.string.sub_fragment_1_page_title);
case 1:
return context.getResources().getString(R.string.sub_fragment_2_page_title);
default:
return null;
}
}
}
当使用 ViewPager
将 Fragments
嵌套在 Fragment
内并滑动功能作为 FragmentManager
需要提供给 Adapter
时,建议使用:getChildFragmentManager()
而不是 getSupportFragmentManager()
或 getFragmentManager()
。因为两者实际上都与 Activities
相关,而不是 getChildFragmentManager()
,如文档所述,与 Fragment
:
相关
Return a private FragmentManager for placing and managing Fragments
inside of this Fragment.
我有一个 Main Activity,它使用 AHBottomNavigationView 作为屏幕底部的菜单。单击不同的菜单项时,它会创建一个与该菜单项对应的新片段,其逻辑如下(为简化此问题而使用的精简 switch 语句):
fragmentManager.beginTransaction().replace(R.id.content_id, New TheFragmentForTheTabClicked).commit();
其中 content_id
是 Main Activity 的 ConstraintLayout 的 ID。
在我的第一个导航菜单项的片段中,还有两个选项卡(使用 TabLayout),它们用另一个片段替换了屏幕 space。这是通过设置在 ViewPager 上的 FragmentPagerAdapter 完成的,因此点击每个选项卡都会更改子片段。所以此时,有一个片段嵌套在一个class的片段中。它通常是这样的:
Main Activity
|
+-- Fragment 1 (selected from AHBottomNavigationView)
| |
| +-- Sub-Fragment 1 (selected by clicking the first tab in Fragment 1)
| |
| +-- Sub-Fragment 2 (selected by clicking the second tab in Fragment 1)
|
+-- Fragment 2 (selected from AHBottomNavigationView)
|
+-- Fragment 3 (selected from AHBottomNavigationView)
|
+-- Fragment 4 (selected from AHBottomNavigationView)
所以我的问题是: 我这样做的方式是否正确,如果不正确,更好的方法是什么? 另外,我发现当我第一次选择 Fragment 1 时,两个选项卡之间的滑动和点击工作正常,但是如果我点击不同的底部导航菜单项(即 Fragment 3)然后返回,我得到以下 2 个问题:
- 未显示任一子片段中的内容
- 在两个选项卡之间滑动不再有效。我必须完全拉过屏幕,而不是一个移动到不同选项卡的动作,因为指示器在两个选项卡之间 "stuck" 中途。
如果我可以提供更多信息,请告诉我,我会的。
Fragment1.java:
package com.mypackage.mypackage;
import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* A simple {@link Fragment} subclass.
*/
public class Fragment1 extends Fragment {
private FragmentActivity mContext;
public Fragment1() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_1, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
// Find the view pager that will allow the user to swipe between fragments
ViewPager viewPager = (ViewPager) getView().findViewById(R.id.viewpager);
// Create an adapter that knows which fragment should be shown on each page
// using getFragmentManager() will work too
Fragment1PagerAdapter adapter = new Fragment1PagerAdapter(mContext.getSupportFragmentManager(), mContext);
// Set the adapter onto the view pager
viewPager.setAdapter(adapter);
TabLayout tabLayout = (TabLayout) getView().findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
}
/**
* Override to set context. This context is used for getSupportFragmentManager in onCreateView
* @param activity
*/
@Override
public void onAttach(Activity activity) {
mContext=(FragmentActivity) activity;
super.onAttach(activity);
}
}
fragment_1.xml
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="@+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabBackground="@color/fragment1TabBackground"
app:tabIndicatorColor="@color/fragment1TabIndicatorColor"/>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"/>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
Fragment1PagerAdapter.java
package com.mypackage.mypackage;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.content.Context;
public class Fragment1PagerAdapter extends FragmentPagerAdapter {
private Context context;
public Fragment1PagerAdapter(FragmentManager fm, Context mContext){
super(fm);
context = mContext;
}
@Override
public Fragment getItem(int position){
if (position == 0){
return new SubFragment1();
}
else{
return new SubFragment2();
}
}
@Override
public int getCount() {return 2;}
@Override
public CharSequence getPageTitle(int position) {
switch(position){
case 0:
return context.getResources().getString(R.string.sub_fragment_1_page_title);
case 1:
return context.getResources().getString(R.string.sub_fragment_2_page_title);
default:
return null;
}
}
}
当使用 ViewPager
将 Fragments
嵌套在 Fragment
内并滑动功能作为 FragmentManager
需要提供给 Adapter
时,建议使用:getChildFragmentManager()
而不是 getSupportFragmentManager()
或 getFragmentManager()
。因为两者实际上都与 Activities
相关,而不是 getChildFragmentManager()
,如文档所述,与 Fragment
:
Return a private FragmentManager for placing and managing Fragments inside of this Fragment.