[英]How to add a Fragment inside a ViewPager using Nested Fragment (Android 4.2)
我有一個帶有三個Fragments
的ViewPager
,每個都顯示一個List
(或Grid
)。
在新的Android API level 17
(Jelly Bean 4.2)中,其中一項功能是Nested Fragments 。 新功能描述說:
如果您使用 ViewPager 創建向左和向右滑動並占用大部分屏幕空間的片段,您現在可以將片段插入到每個片段頁面中。
所以,如果我理解正確,現在我可以創建一個帶有Fragments
(例如里面有一個按鈕)的ViewPager
,並且當用戶按下按鈕時,使用這個新功能在不松開ViewPager
情況下顯示另一個Fragment
。
我已經花了我早上的時間試圖以幾種不同的方式實現這一點,但我無法讓它工作......有人可以添加一個簡單的例子來說明如何實現這一點嗎?
PS:我只對這種方式感興趣,用getChildFragmentManager
來了解它是如何工作的。
假設您已經創建了正確的 xml 布局。 現在在由另一個 Fragment 托管的 ViewPager 中顯示 Fragment 非常簡單。
以下是顯示子片段的父片段:
class ParentViewPagerFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val root = inflater.inflate(R.layout.fragment_parent_viewpager, container, false)
val viewPager = root.findViewById(R.id.viewPager) as ViewPager
// Important: Must use the child FragmentManager or you will see side effects.
viewPager.adapter = MyAdapter(childFragmentManager)
val tabStrip = root.findViewById<TabLayout>(R.id.pagerTabStrip)
tabStrip.setupWithViewPager(viewPager)
return root
}
class MyAdapter internal constructor(fm: FragmentManager) : FragmentPagerAdapter(fm) {
override fun getCount(): Int = 4
override fun getItem(position: Int): Fragment {
val args = Bundle().apply { putInt(ChildFragment.POSITION_KEY, position) }
return ChildFragment.newInstance(args)
}
override fun getPageTitle(position: Int): CharSequence = "Tab $position"
}
companion object {
val TAG: String = ParentViewPagerFragment::class.java.name
}
}
在實例化 FragmentPagerAdapter 時使用Fragment.getChildFragmentManager()很重要。 另請注意,您不能在子片段上使用Fragment.setRetainInstance() ,否則會出現異常。 為簡潔起見,省略了導入。
源代碼可在以下位置找到: https : //github.com/marcoRS/nested-fragments
編輯:如果您想替換ViewPager
頁面的所有內容,您仍然可以使用嵌套片段,但需要進行一些更改。 檢查下面的示例( FragmentActivity
,設置ViewPager
和PagerAdapter
與前面的代碼片段相同):
// this will act as a fragment container, representing one page in the ViewPager
public static class WrapperFragment extends Fragment implements
ReplaceListener {
public static WrapperFragment newInstance(int position) {
WrapperFragment wp = new WrapperFragment();
Bundle args = new Bundle();
args.putInt("position", position);
wp.setArguments(args);
return wp;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
FrameLayout fl = new FrameLayout(getActivity());
fl.setId(10000);
if (getChildFragmentManager().findFragmentByTag("initialTag") == null) {
InitialInnerFragment iif = new InitialInnerFragment();
Bundle args = new Bundle();
args.putInt("position", getArguments().getInt("position"));
iif.setArguments(args);
getChildFragmentManager().beginTransaction()
.add(10000, iif, "initialTag").commit();
}
return fl;
}
// required because it seems the getChildFragmentManager only "sees"
// containers in the View of the parent Fragment.
@Override
public void onReplace(Bundle args) {
if (getChildFragmentManager().findFragmentByTag("afterTag") == null) {
InnerFragment iif = new InnerFragment();
iif.setArguments(args);
getChildFragmentManager().beginTransaction()
.replace(10000, iif, "afterTag").addToBackStack(null)
.commit();
}
}
}
// the fragment that would initially be in the wrapper fragment
public static class InitialInnerFragment extends Fragment {
private ReplaceListener mListener;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mListener = (ReplaceListener) this.getParentFragment();
LinearLayout ll = new LinearLayout(getActivity());
Button b = new Button(getActivity());
b.setGravity(Gravity.CENTER_HORIZONTAL);
b.setText("Frame " + getArguments().getInt("position"));
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Bundle args = new Bundle();
args.putInt("positionInner",
getArguments().getInt("position"));
if (mListener != null) {
mListener.onReplace(args);
}
}
});
ll.setOrientation(LinearLayout.VERTICAL);
ll.addView(b, new LinearLayout.LayoutParams(250,
LinearLayout.LayoutParams.WRAP_CONTENT));
return ll;
}
}
public static class InnerFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
TextView tv = new TextView(getActivity());
tv.setText("InnerFragment in the outher Fragment with position "
+ getArguments().getInt("positionInner"));
return tv;
}
}
public interface ReplaceListener {
void onReplace(Bundle args);
}
快速查看它的工作原理,但可能會出現問題,因為我還沒有對其進行太多測試。
有人可以展示一個簡單的例子來說明如何做到這一點嗎?
使用嵌套片段似乎很容易,直到 Commonsware 提供更詳細的示例,您可以嘗試以下代碼:
public class NestedFragments extends FragmentActivity {
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
ViewPager vp = new ViewPager(this);
vp.setId(5000);
vp.setAdapter(new MyAdapter(getSupportFragmentManager()));
setContentView(vp);
}
private static class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return WrapperFragment.newInstance(position);
}
@Override
public int getCount() {
return 8;
}
}
public static class WrapperFragment extends Fragment {
public static WrapperFragment newInstance(int position) {
WrapperFragment wp = new WrapperFragment();
Bundle args = new Bundle();
args.putInt("position", position);
wp.setArguments(args);
return wp;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
LinearLayout ll = new LinearLayout(getActivity());
FrameLayout innerFragContainer = new FrameLayout(getActivity());
innerFragContainer.setId(1111);
Button b = new Button(getActivity());
b.setText("Frame " + getArguments().getInt("position"));
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
InnerFragment innerFragment = new InnerFragment();
Bundle args = new Bundle();
args.putInt("positionInner",
getArguments().getInt("position"));
innerFragment.setArguments(args);
FragmentTransaction transaction = getChildFragmentManager()
.beginTransaction();
transaction.add(1111, innerFragment).commit();
}
});
ll.setOrientation(LinearLayout.VERTICAL);
ll.addView(b, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
ll.addView(innerFragContainer, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
return ll;
}
}
public static class InnerFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
TextView tv = new TextView(getActivity());
tv.setText("InnerFragment in the outher Fragment with position "
+ getArguments().getInt("positionInner"));
return tv;
}
}
}
我很懶惰,用代碼編寫了所有內容,但我確信它可以與膨脹的 xml 布局一起使用。
我創建了一個 ViewPager,其中包含 3 個元素和 2 個子元素,用於索引 2 和 3,這里是我想要做的。
我已經在 StackOverFlow 之前的問題和答案的幫助下實現了這一點,這里是鏈接。
在您的應用中輕松使用導航組件! 然后在您的偵聽器中,復制此代碼:
findNavController().navigate('Your action Id)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.