Viewpager Adapter getItem 总是调用索引 0 和 1
Viewpager Adapter getItem always called for index 0 and 1
我只是想知道 viewpager
及其适配器总是为索引 0 和 1 调用 getItem()
方法是否是正常行为,即使我立即设置当前位置也是如此。
这是我的代码:
mNewsPagerAdapter = new NewsDetailPagerAdapter(getChildFragmentManager());
mNewsPagerAdapter.updateNewsList(news);
mViewPager = (ViewPager) mView.findViewById(R.id.horizontal_view_pager);
mViewPager.setPageMargin(2);
mViewPager.setPageMarginDrawable(R.color.black);
mViewPager.setAdapter(mNewsPagerAdapter);
mViewPager.setCurrentItem(mCurrentPositionPager, false);
如果我使用此 viewpager
从概述 activity 切换到详细信息 activity,则适配器始终为位置 0 和 1 及之后调用 getItem()
方法getItem()
方法用于 mOriginalPosition
及其邻居的位置。我想知道这是否是正确的行为,或者我是否错过了以正确方式实施它的一些东西。感谢您的帮助:)
编辑:添加了我的适配器代码
public class NewsDetailPagerAdapter extends FragmentStatePagerAdapter {
private SparseArray<Fragment> mPageReferenceMap = new SparseArray<Fragment>();
private ArrayList<News> mNewsList;
public NewsDetailPagerAdapter(FragmentManager fm) {
super(fm);
}
/**
* Setzt die neuen News.
**/
public void updateNewsList(ArrayList<News> list) {
mNewsList = list;
}
@Override
public Fragment getItem(int position) {
Log.d("debug", "getItem position:" + position);
News newsItem = mNewsList.get(position);
NavigationFragment fragment = new NavigationFragment();
mPageReferenceMap.put(position, fragment);
return fragment;
}
@Override
public int getCount() {
return mNewsList.size();
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
public Fragment getFragment(int position) {
return mPageReferenceMap.get(position);
}
}
实际上这是正常行为。事实上,当您将 ViewPager 与适配器相关联时,适配器会创建第一个可见布局(索引 0)结束下一个(索引 1)。这是在 "setAdapter" 中默认完成的。然后,当您设置不同的位置时,适配器将实例化所选索引处的片段,前一个和下一个。
这是通常的 ViewPager setAdapter 代码:
public void setAdapter(PagerAdapter adapter) {
if (mAdapter != null) {
mAdapter.setViewPagerObserver(null);
mAdapter.startUpdate(this);
for (int i = 0; i < mItems.size(); i++) {
final ItemInfo ii = mItems.get(i);
mAdapter.destroyItem(this, ii.position, ii.object);
}
mAdapter.finishUpdate(this);
mItems.clear();
removeNonDecorViews();
mCurItem = 0;
scrollTo(0, 0);
}
final PagerAdapter oldAdapter = mAdapter;
mAdapter = adapter;
mExpectedAdapterCount = 0;
if (mAdapter != null) {
if (mObserver == null) {
mObserver = new PagerObserver();
}
mAdapter.setViewPagerObserver(mObserver);
mPopulatePending = false;
final boolean wasFirstLayout = mFirstLayout;
mFirstLayout = true;
mExpectedAdapterCount = mAdapter.getCount();
if (mRestoredCurItem >= 0) {
mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
setCurrentItemInternal(mRestoredCurItem, false, true);
mRestoredCurItem = -1;
mRestoredAdapterState = null;
mRestoredClassLoader = null;
} else if (!wasFirstLayout) {
populate();
} else {
requestLayout();
}
}
if (mAdapterChangeListener != null && oldAdapter != adapter) {
mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter);
}
}
为了改变 ViewPager 的行为,您可以扩展经典的 ViewPager 覆盖 setAdapter 方法并将 mCurrItem 设置到所需的位置。
希望对您有所帮助
编辑:
经过不同的测试,我们找到了解决方案。
如果在 ViewPager 布局可见后设置 ViewPager 适配器,则加载项 0 和 1。
如果您想避免此行为,但无法在布局可见之前设置适配器(因为您正在等待数据),那么您可以使用此解决方法:
1) 最初将 ViewPager 可见性设置为 GONE
2) 收到所有数据后,更新适配器并设置当前项目值
3) 最后将 ViewPager 可见性设置为 VISIBLE
在这里你可以找到一个例子:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.detail_overview_fragment, container, false);
final int position = getArguments().getInt("position");
final ViewPager viewPager = (ViewPager) v.findViewById(R.id.viewpager);
viewPager.setVisibility(View.GONE);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
viewPager.setAdapter(new PagerAdapter(getChildFragmentManager()));
viewPager.setCurrentItem(position);
viewPager.setVisibility(View.VISIBLE);
}
},5000);
return v;
}
是的,这是 ViewPager 的正常行为,因为它会始终尝试通过呈现受绘图区域限制的选项卡来领先于用户。我个人不建议创建自定义 ViewPager,因为除非您真的知道自己在做什么,否则您几乎肯定会破坏功能。您的适配器 class 应如下所示:
public class YourCustomPagerAdapter extends FragmentStatePagerAdapter {
private List<Fragment> fragmentList = new ArrayList<>();
private List<String> titleList = new ArrayList<>();
public WizardPagerAdapter(FragmentManager fm) {
super(fm);
}
public void addFragment(Fragment fragment, String title) {
fragmentList.add(fragment);
titleList.add(title);
}
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
@Override
public CharSequence getPageTitle(int position) {
super.getPageTitle(position);
return titleList.get(position);
}
@Override
public int getCount() {
return fragmentList.size();
}
}
你应该这样添加你的片段:
@Override
public void onCreate(Bundle savedInstanceState) {
...
YourCustomPagerAdapter adapter = new YourCustomPagerAdapter (getSupportFragmentManager());
adapter.addFragment(FragmentOne.newInstance(), "Frag 1");
adapter.addFragment(FragmentTwo.newInstance(), "Frag 2");
viewPager.setAdapter(adapter);
...
}
我认为错误是适配器:
/**
* Setzt die neuen News.
**/
public void updateNewsList(ArrayList<News> list) {
//mNewsList = list;
mNewsList.clear();
mNewsList.addAll(list);
/**
* Notifies the attached observers that the underlying data has been changed
* and any View reflecting the data set should refresh itself.
*/
this.notifyDataSetChanged();
}
错误原因:此列表是该适配器的不同实体。
这很正常(在我看来也很聪明)。
ViewPager class 有一个名为 mOffscreenPageLimit 的 属性,默认值为 1。此数字决定了 Viewpager 将预加载当前页面左侧和右侧的页面数。例如,您有 10 个页面,当前位置为 5,mOffcreenPageLimit 为 1,则将加载位置 4 和 6 的页面。
您可以通过调用此方法
来更改此 属性
viewpager. setOffscreenPageLimit(int)
如果传入小于1的整数,则无效。
我只是想知道 viewpager
及其适配器总是为索引 0 和 1 调用 getItem()
方法是否是正常行为,即使我立即设置当前位置也是如此。
这是我的代码:
mNewsPagerAdapter = new NewsDetailPagerAdapter(getChildFragmentManager());
mNewsPagerAdapter.updateNewsList(news);
mViewPager = (ViewPager) mView.findViewById(R.id.horizontal_view_pager);
mViewPager.setPageMargin(2);
mViewPager.setPageMarginDrawable(R.color.black);
mViewPager.setAdapter(mNewsPagerAdapter);
mViewPager.setCurrentItem(mCurrentPositionPager, false);
如果我使用此 viewpager
从概述 activity 切换到详细信息 activity,则适配器始终为位置 0 和 1 及之后调用 getItem()
方法getItem()
方法用于 mOriginalPosition
及其邻居的位置。我想知道这是否是正确的行为,或者我是否错过了以正确方式实施它的一些东西。感谢您的帮助:)
编辑:添加了我的适配器代码
public class NewsDetailPagerAdapter extends FragmentStatePagerAdapter {
private SparseArray<Fragment> mPageReferenceMap = new SparseArray<Fragment>();
private ArrayList<News> mNewsList;
public NewsDetailPagerAdapter(FragmentManager fm) {
super(fm);
}
/**
* Setzt die neuen News.
**/
public void updateNewsList(ArrayList<News> list) {
mNewsList = list;
}
@Override
public Fragment getItem(int position) {
Log.d("debug", "getItem position:" + position);
News newsItem = mNewsList.get(position);
NavigationFragment fragment = new NavigationFragment();
mPageReferenceMap.put(position, fragment);
return fragment;
}
@Override
public int getCount() {
return mNewsList.size();
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
public Fragment getFragment(int position) {
return mPageReferenceMap.get(position);
}
}
实际上这是正常行为。事实上,当您将 ViewPager 与适配器相关联时,适配器会创建第一个可见布局(索引 0)结束下一个(索引 1)。这是在 "setAdapter" 中默认完成的。然后,当您设置不同的位置时,适配器将实例化所选索引处的片段,前一个和下一个。
这是通常的 ViewPager setAdapter 代码:
public void setAdapter(PagerAdapter adapter) {
if (mAdapter != null) {
mAdapter.setViewPagerObserver(null);
mAdapter.startUpdate(this);
for (int i = 0; i < mItems.size(); i++) {
final ItemInfo ii = mItems.get(i);
mAdapter.destroyItem(this, ii.position, ii.object);
}
mAdapter.finishUpdate(this);
mItems.clear();
removeNonDecorViews();
mCurItem = 0;
scrollTo(0, 0);
}
final PagerAdapter oldAdapter = mAdapter;
mAdapter = adapter;
mExpectedAdapterCount = 0;
if (mAdapter != null) {
if (mObserver == null) {
mObserver = new PagerObserver();
}
mAdapter.setViewPagerObserver(mObserver);
mPopulatePending = false;
final boolean wasFirstLayout = mFirstLayout;
mFirstLayout = true;
mExpectedAdapterCount = mAdapter.getCount();
if (mRestoredCurItem >= 0) {
mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
setCurrentItemInternal(mRestoredCurItem, false, true);
mRestoredCurItem = -1;
mRestoredAdapterState = null;
mRestoredClassLoader = null;
} else if (!wasFirstLayout) {
populate();
} else {
requestLayout();
}
}
if (mAdapterChangeListener != null && oldAdapter != adapter) {
mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter);
}
}
为了改变 ViewPager 的行为,您可以扩展经典的 ViewPager 覆盖 setAdapter 方法并将 mCurrItem 设置到所需的位置。
希望对您有所帮助
编辑:
经过不同的测试,我们找到了解决方案。
如果在 ViewPager 布局可见后设置 ViewPager 适配器,则加载项 0 和 1。 如果您想避免此行为,但无法在布局可见之前设置适配器(因为您正在等待数据),那么您可以使用此解决方法:
1) 最初将 ViewPager 可见性设置为 GONE
2) 收到所有数据后,更新适配器并设置当前项目值
3) 最后将 ViewPager 可见性设置为 VISIBLE
在这里你可以找到一个例子:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.detail_overview_fragment, container, false);
final int position = getArguments().getInt("position");
final ViewPager viewPager = (ViewPager) v.findViewById(R.id.viewpager);
viewPager.setVisibility(View.GONE);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
viewPager.setAdapter(new PagerAdapter(getChildFragmentManager()));
viewPager.setCurrentItem(position);
viewPager.setVisibility(View.VISIBLE);
}
},5000);
return v;
}
是的,这是 ViewPager 的正常行为,因为它会始终尝试通过呈现受绘图区域限制的选项卡来领先于用户。我个人不建议创建自定义 ViewPager,因为除非您真的知道自己在做什么,否则您几乎肯定会破坏功能。您的适配器 class 应如下所示:
public class YourCustomPagerAdapter extends FragmentStatePagerAdapter {
private List<Fragment> fragmentList = new ArrayList<>();
private List<String> titleList = new ArrayList<>();
public WizardPagerAdapter(FragmentManager fm) {
super(fm);
}
public void addFragment(Fragment fragment, String title) {
fragmentList.add(fragment);
titleList.add(title);
}
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
@Override
public CharSequence getPageTitle(int position) {
super.getPageTitle(position);
return titleList.get(position);
}
@Override
public int getCount() {
return fragmentList.size();
}
}
你应该这样添加你的片段:
@Override
public void onCreate(Bundle savedInstanceState) {
...
YourCustomPagerAdapter adapter = new YourCustomPagerAdapter (getSupportFragmentManager());
adapter.addFragment(FragmentOne.newInstance(), "Frag 1");
adapter.addFragment(FragmentTwo.newInstance(), "Frag 2");
viewPager.setAdapter(adapter);
...
}
我认为错误是适配器:
/**
* Setzt die neuen News.
**/
public void updateNewsList(ArrayList<News> list) {
//mNewsList = list;
mNewsList.clear();
mNewsList.addAll(list);
/**
* Notifies the attached observers that the underlying data has been changed
* and any View reflecting the data set should refresh itself.
*/
this.notifyDataSetChanged();
}
错误原因:此列表是该适配器的不同实体。
这很正常(在我看来也很聪明)。 ViewPager class 有一个名为 mOffscreenPageLimit 的 属性,默认值为 1。此数字决定了 Viewpager 将预加载当前页面左侧和右侧的页面数。例如,您有 10 个页面,当前位置为 5,mOffcreenPageLimit 为 1,则将加载位置 4 和 6 的页面。
您可以通过调用此方法
来更改此 属性viewpager. setOffscreenPageLimit(int)
如果传入小于1的整数,则无效。