Android 调用 setCurrentItem(0) 时不会触发 onPageSelected
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11794269/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
onPageSelected isn't triggered when calling setCurrentItem(0)
提问by jpihl
I have an Activity with a ViewPager which displays a bunch of pictures. When it starts the ViewPager's position is set based on what the user selected in a previous Activity. Similar to a gallery.
我有一个带有 ViewPager 的活动,它显示一堆图片。当它启动时,ViewPager 的位置是根据用户在上一个 Activity 中选择的内容设置的。类似于画廊。
I want the onPageSelected to be called every time a new page is selected, i.e. when the Activity is first opened or when the user slides to a new page.
我希望每次选择新页面时都调用 onPageSelected,即第一次打开 Activity 或用户滑动到新页面时。
I set the starting point like so:
我这样设置起点:
mPager.setCurrentItem(index);
Everything works, except when setCurrentItem called with index set to 0 as this will not trigger onPageSelected.
一切正常,除非当 setCurrentItem 调用时索引设置为 0,因为这不会触发 onPageSelected。
mPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int index) {
Log.d(TAG, "onPageSelected " + index);
}
...
}
So my question is; is this a bug, and if so what can I do about it?
所以我的问题是;这是一个错误,如果是这样我该怎么办?
回答by technicalflaw
The cleanest solution I've found to this so far is to take a reference to the onPageChangeListener you set on the ViewPager (since I don't think there's a ViewPager.getOnPageChangeListener() method), then after you've set the ViewPager's adapter, call:
到目前为止,我找到的最干净的解决方案是引用您在 ViewPager 上设置的 onPageChangeListener(因为我认为没有 ViewPager.getOnPageChangeListener() 方法),然后在您设置 ViewPager 的适配器之后, 称呼:
onPageChangeListener.onPageSelected(viewPager.getCurrentItem());
However, the fragment for the page at the current index won't have been instantiated yet (at least if you're using FragmentStatePagerAdapter), so you may need to wrap it in a runnable, ala:
但是,当前索引处的页面片段还没有被实例化(至少如果你使用 FragmentStatePagerAdapter),所以你可能需要将它包装在一个可运行的文件中,ala:
viewPager.post(new Runnable(){
@Override
public void run() {
onPageChangeListener.onPageSelected(viewPager.getCurrentItem());
}
});
Also, if within the onPageSelected handler you need a reference to the fragment, you'll have to do that yourself. I use an abstract base class for my FragmentStatePagerAdapter which overrides the instantiate and destroy methods, and adds/removes the fragments from a SparseArray.
此外,如果在 onPageSelected 处理程序中需要对片段的引用,则必须自己执行此操作。我为 FragmentStatePagerAdapter 使用了一个抽象基类,它覆盖了实例化和销毁方法,并从 SparseArray 添加/删除了片段。
回答by jpihl
Ok, so I haven't been able to figure out whether this is a bug (or a feature). But I thought I'd share how a possible solution to the problem could look..
好的,所以我一直无法弄清楚这是否是错误(或功能)。但我想我会分享一个可能的问题解决方案看起来如何..
Write the functionality you wish to perform in a method in the Activity and then call this in the onPageSelected method.
在 Activity 的方法中编写您希望执行的功能,然后在 onPageSelected 方法中调用它。
mPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int index) {
myOnPageSelectedLogic(index);
}
...
}
And then right after calling
然后在打电话之后
setCurrentItem(index);
in the Activity, add the following if statement
在Activity中,添加以下if语句
if(index == 0) {
myOnPageSelectedLogic(0);
}
It's not super pretty but I hope it helps someone :)
它不是超级漂亮,但我希望它可以帮助某人:)
回答by ldn0x7dc
Actually I think this is a BUG. I've check the source code of ViewPager and found the only trigger of onPageSelected:
其实我觉得这是一个BUG。我已经检查ViewPager的源代码,发现唯一的触发使用onPageSelected:
if (dispatchSelected && mOnPageChangeListener != null) {
mOnPageChangeListener.onPageSelected(item);
}
Above, variable dispatchSelectedis determined by code:
上面,变量dispatchSelected是由代码决定的:
final boolean dispatchSelected = mCurItem != item;
//item is what you passed to setCurrentItem(item)
And, variable mCurItemis defined and initialized as:
并且,变量mCurItem被定义和初始化为:
private int mCurItem; // Index of currently displayed page.
So mCurItemis default to 0. When calling setCurrentItem(0), dispatchSelectedwill be false thus onPageSelected() will not be dispatched.
所以mCurItem默认为 0。调用 setCurrentItem(0) 时,dispatchSelected将为 false,因此 onPageSelected() 不会被调度。
Now we should understand why calling setCurrentItem(0) is a problem while setCurrentItem(1, or 2, 3...) is not.
现在我们应该明白为什么调用 setCurrentItem(0) 是一个问题,而 setCurrentItem(1, or 2, 3...) 不是。
How to solve this problem:
如何解决这个问题呢:
Copy the code of ViewPager to your own project and fix it:
from final boolean dispatchSelected = mCurItem != item; //the old line to final boolean dispatchSelected = mCurItem != item || mFirstLayout; //the new line
then use your own ViewPager.
Since you consciously called setCurrentItem(0) and have a refrence to the OnPageChangedListener, dispatch the onPageSelected() by yourself.
听楼下怎么说...
将ViewPager的代码复制到自己的项目中并修复:
from final boolean dispatchSelected = mCurItem != item; //the old line to final boolean dispatchSelected = mCurItem != item || mFirstLayout; //the new line
然后使用您自己的 ViewPager。
由于您有意识地调用了 setCurrentItem(0) 并参考了 OnPageChangedListener,因此请自行调度 onPageSelected()。
听楼下说...
回答by maturecheese
The following solution seems to work for me. i.e. I get a callback at position 0 when the viewpager is first loaded and for all subsequent selections either from user scrolling or a setCurrentItem(x) call. I haven't observed any undesired behaviour.
以下解决方案似乎对我有用。即,当 viewpager 首次加载时,以及来自用户滚动或 setCurrentItem(x) 调用的所有后续选择时,我在位置 0 处收到回调。我没有观察到任何不受欢迎的行为。
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (positionOffsetPixels == 0) {
//Do something on selected page at position
}
}
@Override
public void onPageSelected(int position) {}
@Override
public void onPageScrollStateChanged(int state) {}
});
回答by Dartan Li
public class PageChangeListener implements ViewPager.OnPageChangeListener {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_IDLE && getCurrentItem() == 0) {
//this indicate viewpager finish scroll and page at position 0 is selected.
}
回答by Vlad
The simplest solution will be using of function e.g.
最简单的解决方案是使用函数,例如
viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrollStateChanged(int state) {}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
@Override
public void onPageSelected(int position) {
onPage(position);
}
});
// call first time
onPage(0);
private void onPage(int position) {
//...
}
回答by Kirill Kulakov
You can extend the ViewPager
and call the Listener by yourself when the position is changed from 0 to 0
ViewPager
当位置从0变为0时,你可以自己扩展和调用监听器
public class BetterViewPager extends ViewPager {
public BetterViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
// we some the listner
protected OnPageChangeListener listener;
@Override
public void setOnPageChangeListener(OnPageChangeListener listener) {
super.setOnPageChangeListener(listener);
this.listener = listener;
}
@Override
public void setCurrentItem(int item) {
// when you pass set current item to 0,
// the listener won't be called so we call it on our own
boolean invokeMeLater = false;
if(super.getCurrentItem() == 0 && item == 0)
invokeMeLater = true;
super.setCurrentItem(item);
if(invokeMeLater && listener != null)
listener.onPageSelected(0);
}
}
回答by marwinXXII
onPageSelected
is not triggered for page which is opened first. For this case I manually perform all needed actions. Also, I suppose that call to onPageSelected(0)
should work too.
onPageSelected
不会为首先打开的页面触发。对于这种情况,我手动执行所有需要的操作。另外,我认为调用 to 也onPageSelected(0)
应该起作用。
回答by Erik K.
If the ViewPager is in a fragment, in the onViewCreated method, call mPager.setOnPageChangeListener(this)
如果ViewPager在fragment中,在onViewCreated方法中调用mPager.setOnPageChangeListener(this)
回答by u2593833
if you don't care screen animotion try
如果你不关心屏幕动画试试
pager.setCurrentItem(1);
pager.setCurrentItem(0);