【问题标题】:Showing specified page when view pager is first created首次创建 viewpager 时显示特定页面
【发布时间】:2014-06-12 07:15:40
【问题描述】:

我有一个包含ViewPager 的片段。此ViewPager 由使用CursorPagerAdapter 支持。游标由LoaderCallbacks 管理。我在这里使用 v4 支持库。

我想要的是创建片段并让视图寻呼机显示指定页面,而不是从第 0 页开始。

我知道ViewPager 有一个setCurrentItem() 方法,但是在创建ViewPager 时可能还没有加载数据。我需要监听适配器的数据集更改,如果这是第一次这样的更改,则在ViewPager 上调用setCurrentItem()

但是PagerAdapter 类不导出registerDataSetObserver() 方法;它具有package 而不是public 访问权限(至少在v4 支持库中)。

我所做的,在我看来很像一个 hack,如下:

class ItemPagerFragment extends SherlockFragment implements LoaderCallbacks<Cursor> {

    private CursorPagerAdapter mAdapter;
    private ViewPager mPager;
    private int mInitialPageToShow;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAdapter = new CursorPagerAdapter() {
            @Override public void notifyDataSetChanged() {
                super.notifyDataSetChanged();
                setInitialPageIfRequired();
            }
        }; 
        getActivity().getSupportLoaderManager().initLoader(LOADER_ID, null, this);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup group, Bundle saved) {
        View view = inflater.inflate(R.layout.items_pager, group, false);
        mPager = (ViewPager) view.findViewById(R.id.pager);
        mPager.setAdapter(mAdapter);
        setInitialPageIfRequired();
        return view;
    }

    private boolean initialPageSet = false;

    private synchronized void setInitialPageIfRequired() {
        // Set the current page of the pager if (a) this is the 
        // first time attempting to set the page and (b) the 
        // pager exists and (c) the adapter has data.
        if (!initialPageSet && mPager != null && mAdapter.getCount() > 0) {
            mPager.setCurrentItem(mInitialPageToShow);
            initialPageSet = true;
        }
    }

}

在将数据加载到适配器(在onCreate() 方法中)和在onCreateView() 方法中创建ViewPager 之间存在竞争条件。因此,可以在 (a) 寻呼机存在但第一次加载数据或 (b) 在创建寻呼机之前加载数据时设置当前页面。

我已尝试处理上述两种情况,但我认为必须有一种替代方法,使用观察者更强大(并且希望更简单)。

【问题讨论】:

  • 你能把CursorPagerAdapter的代码贴出来吗?
  • @Luksprog CursorPagerAdapter 类扩展 FragmentPagerAdapter 并使用光标处理 getCount()getItem()。它还有一个swapCursor() 方法(参见CursorAdapter 类),由LoaderCallbacks 方法调用(上面我的代码sn-ps 中没有显示)。我已将 CursorPagerAdapter 代码放在此处的 pastebin 上:pastebin.com/XTx5HfKS
  • 如果我在你的位置,我会从ViewPager 开始Fragments 与我当时拥有的数据(如果我没有任何数据,则显示一个空白的东西,或者loading) 并在加载器的onLoadFinished 回调中,我会将数据放在主Fragment 的字段中,并让ViewPager 片段知道数据可供它们使用并且它们应该更新。
  • @Luksprog 感谢您的评论。实际上,你提到的事情已经发生了。 onLoadFinished 回调调用适配器的swapCursor 方法,该方法将调用notifyDataSetChanged。这是在上面的代码 sn-p 中处理的。但是,不能保证在适配器收到数据集更改通知时寻呼机将存在。
  • 如果这就是你所害怕的,那你为什么不在onActivityCreated 中启动加载器呢?

标签: android android-viewpager android-cursorloader android-pageradapter


【解决方案1】:

等待initLoader 直到寻呼机存在后,检查布尔标志并仅在第一次调用onLoadFinished 时执行setCurrentItem

class ItemPagerFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {

    private CursorPagerAdapter mAdapter;
    private ViewPager mPager;
    private int mInitialPageToShow;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup group, Bundle saved) {
        View view = inflater.inflate(R.layout.items_pager, group, false);
        mPager = (ViewPager) view.findViewById(R.id.pager);
        mAdapter = new CursorPagerAdapter(getFragmentManager());
        mPager.setAdapter(mAdapter);
        return view;
    }

    @Override
    public void onViewCreated(View view, Bundle saved) {
        super.onViewCreated(view, saved);
        ...
        getLoaderManager().initLoader(LOADER_ID, null, this);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
        mAdapter.swapCursor(cursor);
        setInitialPageIfRequired();
    }

    private boolean initialPageSet = false;

    private synchronized void setInitialPageIfRequired() {
        // Set the current page of the pager if (a) this is the 
        // first time attempting to set the page and (b) the 
        // pager exists and (c) the adapter has data.
        if (!initialPageSet && mPager != null && mAdapter.getCount() > 0) {
            mPager.setCurrentItem(mInitialPageToShow);
            initialPageSet = true;
        }
    }
}

注意:这个 sn-p 假定 v13 支持库,但它应该与 v4 相同。

【讨论】:

  • 配置更改会发生什么?在savedInstanceState 包中保存/检索mInitialPageToShow 会更好吗?
猜你喜欢
  • 2013-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多