in Android ~ read.

Android实现ListView(GridView)item嵌入ViewPager

本文地址:https://chihoc.com/viewPager-embedded-in-listview/
欢迎转载,请注明出处,谢谢

最近在实现一个界面,要求在ListView的每个item里面加入一个ViewPager。数据从服务器加载,以决定有多少个item,每个ViewPager有多少页。

本来以为实现并不难,直接使用之前封装的Listview,以ViewPager作为Item编写响应的xml文件,直接渲染就完事了。结果就遇到了坑。

ViewPager使用的是FragmentPagerAdapter,那当然FragmentManager都是统一是用ActivityFragmentManager

viewPager.setAdapter(new FragmentPagerAdapter(mActivity.getSupportFragmentManager()) {}

结果运行一看,只有第一个Item的视图出来了,其他都出不来了。

一步步分析找原因。

FragmentPagerAdapter中,我们可以看到instantiateItem方法,它是在用于显示ViewPageritem的时候调用的。

@Override
public Object instantiateItem(ViewGroup container, int position) {
    if (mCurTransaction == null) {
        mCurTransaction = mFragmentManager.beginTransaction();
    }

    final long itemId = getItemId(position);

    // Do we already have this fragment?
    String name = makeFragmentName(container.getId(), itemId);
    Fragment fragment = mFragmentManager.findFragmentByTag(name);
    if (fragment != null) {
        if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
        mCurTransaction.attach(fragment);
    } else {
        fragment = getItem(position);
        if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
        mCurTransaction.add(container.getId(), fragment,
                makeFragmentName(container.getId(), itemId));
    }
    if (fragment != mCurrentPrimaryItem) {
        fragment.setMenuVisibility(false);
        fragment.setUserVisibleHint(false);
    }

    return fragment;
}

重点在于这条语句:

Fragment fragment = mFragmentManager.findFragmentByTag(name);

它会从FragmentManager中找到对应nameFragment,以判断是否应该初始化新的一个Fragment

那这个name到底是什么呢?它是由方法makeFragmentName返回的。

private static String makeFragmentName(int viewId, long id) {
    return "android:switcher:" + viewId + ":" + id;
}

参数有两个,根据前面的调用可以看到,分别是ViewPager的id,和getItemId返回的ItemId

真相大白

由于我们使用xml布局,然后给了一样的id,同时使用的默认的getItemId方法,因此最终得出的name是一样的。所以只有当第一个ViewPager渲染时,才正确初始化Fragment

解决方法有两个:

  1. ViewHolder代码修改每个ViewPager的id
  2. 继承FragmentPagerAdapter,派生子类重写getItemId方法,根据不同的ViewPager返回不同的ItemId。