我试图使用片段与一个ViewPager使用FragmentPagerAdapter。
我想要实现的是替换一个片段,位于ViewPager的第一页,与另一个。
寻呼机由两个页面组成。第一个是FirstPagerFragment,第二个是SecondPagerFragment。点击第一页的一个按钮。我想用NextFragment替换FirstPagerFragment。
下面是我的代码。
public class FragmentPagerActivity extends FragmentActivity {
static final int NUM_ITEMS = 2;
MyAdapter mAdapter;
ViewPager mPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_pager);
mAdapter = new MyAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
}
/**
* Pager Adapter
*/
public static class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return NUM_ITEMS;
}
@Override
public Fragment getItem(int position) {
if(position == 0) {
return FirstPageFragment.newInstance();
} else {
return SecondPageFragment.newInstance();
}
}
}
/**
* Second Page FRAGMENT
*/
public static class SecondPageFragment extends Fragment {
public static SecondPageFragment newInstance() {
SecondPageFragment f = new SecondPageFragment();
return f;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Log.d("DEBUG", "onCreateView");
return inflater.inflate(R.layout.second, container, false);
}
}
/**
* FIRST PAGE FRAGMENT
*/
public static class FirstPageFragment extends Fragment {
Button button;
public static FirstPageFragment newInstance() {
FirstPageFragment f = new FirstPageFragment();
return f;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Log.d("DEBUG", "onCreateView");
View root = inflater.inflate(R.layout.first, container, false);
button = (Button) root.findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
FragmentTransaction trans = getFragmentManager().beginTransaction();
trans.replace(R.id.first_fragment_root_id, NextFragment.newInstance());
trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
trans.addToBackStack(null);
trans.commit();
}
});
return root;
}
/**
* Next Page FRAGMENT in the First Page
*/
public static class NextFragment extends Fragment {
public static NextFragment newInstance() {
NextFragment f = new NextFragment();
return f;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Log.d("DEBUG", "onCreateView");
return inflater.inflate(R.layout.next, container, false);
}
}
}
...这里是XML文件
fragment_pager.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:padding="4dip"
android:gravity="center_horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</android.support.v4.view.ViewPager>
</LinearLayout>
first.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/first_fragment_root_id"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button android:id="@+id/button"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="to next"/>
</LinearLayout>
现在的问题是……我应该使用哪个ID
trans.replace(R.id.first_fragment_root_id, NextFragment.newInstance());
?
如果我用r。id。first_fragment_root_id,替换工作,但Hierarchy Viewer显示一个奇怪的行为,如下所示。
一开始的情况是
更换后的情况是
正如你所看到的,有一些错误,我希望在替换片段后找到与第一张图片中相同的状态。
我做了一些类似于wize的事情,但在我的回答中,你可以随时在两个片段之间更改。在改变屏幕方向之类的时候,我遇到了一些问题。这是PagerAdapter的样子:
public class MyAdapter extends FragmentPagerAdapter
{
static final int NUM_ITEMS = 2;
private final FragmentManager mFragmentManager;
private Fragment mFragmentAtPos0;
private Map<Integer, String> mFragmentTags;
private boolean isNextFragment=false;
public MyAdapter(FragmentManager fm)
{
super(fm);
mFragmentManager = fm;
mFragmentTags = new HashMap<Integer, String>();
}
@Override
public Fragment getItem(int position)
{
if (position == 0)
{
if (isPager) {
mFragmentAtPos0 = new FirstPageFragment();
} else {
mFragmentAtPos0 = new NextFragment();
}
return mFragmentAtPos0;
}
else
return SecondPageFragment.newInstance();
}
@Override
public int getCount()
{
return NUM_ITEMS;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Object obj = super.instantiateItem(container, position);
if (obj instanceof Fragment) {
// record the fragment tag here.
Fragment f = (Fragment) obj;
String tag = f.getTag();
mFragmentTags.put(position, tag);
}
return obj;
}
public void onChange(boolean isNextFragment) {
if (mFragmentAtPos0 == null)
mFragmentAtPos0 = getFragment(0);
if (mFragmentAtPos0 != null)
mFragmentManager.beginTransaction().remove(mFragmentAtPos0).commit();
if (!isNextFragment) {
mFragmentAtFlashcards = new FirstPageFragment();
} else {
mFragmentAtFlashcards = new NextFragment();
}
notifyDataSetChanged();
}
@Override
public int getItemPosition(Object object)
{
if (object instanceof FirstPageFragment && mFragmentAtPos0 instanceof NextFragment)
return POSITION_NONE;
if (object instanceof NextFragment && mFragmentAtPos0 instanceof FirstPageFragment)
return POSITION_NONE;
return POSITION_UNCHANGED;
}
public Fragment getFragment(int position) {
String tag = mFragmentTags.get(position);
if (tag == null)
return null;
return mFragmentManager.findFragmentByTag(tag);
}
}
我在适配器容器活动中实现的侦听器,用于在附加片段时将其放到片段中,这是活动:
public class PagerContainerActivity extends AppCompatActivity implements ChangeFragmentListener {
//...
@Override
public void onChange(boolean isNextFragment) {
if (pagerAdapter != null)
pagerAdapter.onChange(isNextFragment);
}
//...
}
然后在片段中放置侦听器,当附加调用它:
public class FirstPageFragment extends Fragment{
private ChangeFragmentListener changeFragmentListener;
//...
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
changeFragmentListener = ((PagerContainerActivity) activity);
}
@Override
public void onDetach() {
super.onDetach();
changeFragmentListener = null;
}
//...
//in the on click to change the fragment
changeFragmentListener.onChange(true);
//...
}
最后是听众:
public interface changeFragmentListener {
void onChange(boolean isNextFragment);
}
我找到了一个简单的解决方案,即使你想在中间添加新的片段或替换当前片段,它也能很好地工作。在我的解决方案中,您应该重写getItemId(),它应该为每个片段返回唯一的id。不是默认的位置。
就是这样:
public class DynamicPagerAdapter extends FragmentPagerAdapter {
private ArrayList<Page> mPages = new ArrayList<Page>();
private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
public DynamicPagerAdapter(FragmentManager fm) {
super(fm);
}
public void replacePage(int position, Page page) {
mPages.set(position, page);
notifyDataSetChanged();
}
public void setPages(ArrayList<Page> pages) {
mPages = pages;
notifyDataSetChanged();
}
@Override
public Fragment getItem(int position) {
if (mPages.get(position).mPageType == PageType.FIRST) {
return FirstFragment.newInstance(mPages.get(position));
} else {
return SecondFragment.newInstance(mPages.get(position));
}
}
@Override
public int getCount() {
return mPages.size();
}
@Override
public long getItemId(int position) {
// return unique id
return mPages.get(position).getId();
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
while (mFragments.size() <= position) {
mFragments.add(null);
}
mFragments.set(position, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
mFragments.set(position, null);
}
@Override
public int getItemPosition(Object object) {
PagerFragment pagerFragment = (PagerFragment) object;
Page page = pagerFragment.getPage();
int position = mFragments.indexOf(pagerFragment);
if (page.equals(mPages.get(position))) {
return POSITION_UNCHANGED;
} else {
return POSITION_NONE;
}
}
}
注意:在这个例子中,FirstFragment和SecondFragment扩展了抽象类PageFragment,它有方法getPage()。
要替换ViewPager中的片段,你可以将ViewPager、PagerAdapter和FragmentStatePagerAdapter类的源代码移动到你的项目中,并添加以下代码。
分为:viewpage:
public void notifyItemChanged(Object oldItem, Object newItem) {
if (mItems != null) {
for (ItemInfo itemInfo : mItems) {
if (itemInfo.object.equals(oldItem)) {
itemInfo.object = newItem;
}
}
}
invalidate();
}
FragmentStatePagerAdapter:
public void replaceFragmetns(ViewPager container, Fragment oldFragment, Fragment newFragment) {
startUpdate(container);
// remove old fragment
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
int position = getFragmentPosition(oldFragment);
while (mSavedState.size() <= position) {
mSavedState.add(null);
}
mSavedState.set(position, null);
mFragments.set(position, null);
mCurTransaction.remove(oldFragment);
// add new fragment
while (mFragments.size() <= position) {
mFragments.add(null);
}
mFragments.set(position, newFragment);
mCurTransaction.add(container.getId(), newFragment);
finishUpdate(container);
// ensure getItem returns newFragemtn after calling handleGetItemInbalidated()
handleGetItemInbalidated(container, oldFragment, newFragment);
container.notifyItemChanged(oldFragment, newFragment);
}
protected abstract void handleGetItemInbalidated(View container, Fragment oldFragment, Fragment newFragment);
protected abstract int getFragmentPosition(Fragment fragment);
handleGetItemInvalidated()确保下一次调用getItem()后返回newFragment
getFragmentPosition()返回片段在适配器中的位置。
现在,替换片段调用
mAdapter.replaceFragmetns(mViewPager, oldFragment, newFragment);
如果你对一个示例项目感兴趣,请向我索取资源。