Android ViewPager setCurrentItem(pageId, true) 不平滑滚动
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11962268/
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
ViewPager setCurrentItem(pageId, true) does NOT smoothscroll
提问by Code Droid
I am compiling on SDK 4.03, Samsung Infuse Android 2.2, Support Library for Android 4, and using ViewPager in my app, actual swipe works fine, but when I do
我正在编译 SDK 4.03、Samsung Infuse Android 2.2、Android 4 支持库,并在我的应用程序中使用 ViewPager,实际滑动工作正常,但是当我这样做时
viewPager.setCurrentItem(id); // , or
viewPager.setCurrentItem(id, true);
It does not smooth scroll, but switches views instantly. Although the documentation clearly states that that is the purpose setting the second argument to true. Whats up with this?
它不会平滑滚动,但会立即切换视图。尽管文档明确指出这是将第二个参数设置为 true 的目的。这是怎么回事?
回答by Marc Van Daele
I've fixed this by creating a MyViewPager that overrides the ViewPager.mScroller using reflection.
我通过创建一个使用反射覆盖 ViewPager.mScroller 的 MyViewPager 解决了这个问题。
public class MyViewPager extends ViewPager {
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
setMyScroller();
}
private void setMyScroller() {
try {
Class<?> viewpager = ViewPager.class;
Field scroller = viewpager.getDeclaredField("mScroller");
scroller.setAccessible(true);
scroller.set(this, new MyScroller(getContext()));
} catch (Exception e) {
e.printStackTrace();
}
}
public class MyScroller extends Scroller {
public MyScroller(Context context) {
super(context, new DecelerateInterpolator());
}
@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, 1000 /*1 secs*/);
}
}
}
回答by tegbird
This is what i did. I overrode the package-private method smoothScrollTo
in ViewPager
by putting my own custom subclass in the same package. It was being passed a value of zero, which causes the snapping behavior instead of the smooth scroll.
这就是我所做的。我通过将我自己的自定义子类放在同一个包smoothScrollTo
中ViewPager
来覆盖包私有方法。它被传递了一个零值,这会导致捕捉行为而不是平滑滚动。
package android.support.v4.view;
import android.content.Context;
import android.util.AttributeSet;
public class MyViewPager extends ViewPager {
public MyViewPager(Context context) {
super(context);
}
public MyViewPager(Context context, AttributeSet attr) {
super(context, attr);
}
void smoothScrollTo(int x, int y, int velocity) {
super.smoothScrollTo(x, y, 1);
}
}
It worked great, if you want you can calculate and provide actual velocity ISO of just 1.
效果很好,如果您愿意,您可以计算并提供仅为 1 的实际速度 ISO。
回答by ACengiz
I called setCurrentItem
function in a handler and it worked fine for me.
我setCurrentItem
在处理程序中调用了函数,它对我来说很好用。
new Handler().post(new Runnable() {
@Override
public void run() {
myViewPager.setCurrentItem(1, true);
}
});
Hope this helps.
希望这可以帮助。
回答by XNiiNJA
I'm aware this thread it pretty old, but this is one of the top Google results. I've been going back and forth on how to solve this problem for quite a bit now. None of the solutions above helped me at all. However, I did find a solution that works for me.
我知道这个线程很旧,但这是谷歌搜索结果之一。我一直在反复讨论如何解决这个问题。上述解决方案都没有帮助我。但是,我确实找到了适合我的解决方案。
What my setup currently looks like is a listview inside a viewpager. When you click on one of the views it creates a new page and scrolls to it. This was very snappy before, but it seems as though this is because I was calling
我的设置目前看起来像一个 viewpager 中的列表视图。当您单击其中一个视图时,它会创建一个新页面并滚动到该页面。以前这很活泼,但似乎这是因为我在打电话
mViewPager.setCurrentItem(intIndex, true);
from inside my OnClickEvent. The viewpager doesn't like this for some reason, so instead, I made this function. It creates a new thread that runs a runnable on the UI thread. This runnable is what tells the ViewPager to scroll to a certain item.
从我的 OnClickEvent 内部。由于某种原因,viewpager 不喜欢这个,所以我做了这个功能。它创建了一个在 UI 线程上运行可运行的新线程。这个 runnable 告诉 ViewPager 滚动到某个项目。
public static void scrollToIndex(int index) {
final int intIndex = index;
//We're going to make another thread to separate ourselves from whatever
//thread we are in
Thread sepThread = new Thread(new Runnable(){
public void run()
{
//Then, inside that thread, run a runnable on the ui thread.
//MyActivity.getContext() is a static function that returns the
//context of the activity. It's useful in a pinch.
((Activity)MyActivity.getContext()).runOnUiThread(new Runnable(){
@Override
public void run() {
if (mSlidingTabLayout != null)
{
//I'm using a tabstrip with this as well, make sure
//the tabstrip is updated, or else it won't scroll
//correctly
if(mSlidingTabLayout.getTabStripChildCount() <= intIndex)
mSlidingTabLayout.updateTabStrip();
//Inside this thread is where you call setCurrentItem
mViewPager.setCurrentItem(intIndex, true);
}
}
});
}
});
sepThread.start();
}
I hope I have at least helped someone with this problem. Good luck!
我希望我至少帮助过这个问题的人。祝你好运!
Edit: Looking over my answer, I'm pretty sure you can just run on the ui thread, and it should work. Take that with a grain of salt though, I haven't tested it yet.
编辑:查看我的答案,我很确定您可以在 ui 线程上运行,并且它应该可以工作。尽管如此,我还没有测试过。
回答by Thomas W.
I′ve created this class because I wasn't fully satisfied with the above solutions
我创建这个类是因为我对上述解决方案并不完全满意
The class overrides setCurrentItem(int item, boolean smoothScroll)
and uses reflection to keep this method as original as possible. The key is that velocity is not 0.
You only have to replace your current ViewPager
with this MyViewPager
class and use it like normally:
该类覆盖setCurrentItem(int item, boolean smoothScroll)
并使用反射来尽可能保持此方法的原始性。关键是速度不是 0。你只需ViewPager
要用这个MyViewPager
类替换你的 current并像往常一样使用它:
import android.content.Context;
import android.util.AttributeSet;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import androidx.viewpager.widget.ViewPager;
public class MyViewPager extends ViewPager {
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* Set the currently selected page. If the ViewPager has already been through its first
* layout with its current adapter there will be a smooth animated transition between
* the current item and the specified item.
*
* @param item Item index to select
* @param smoothScroll True to smoothly scroll to the new item, false to transition immediately
*/
@Override
public void setCurrentItem(int item, boolean smoothScroll) {
final Class<?> viewpager = ViewPager.class;
int velocity = 1;
try {
Field mPopulatePending = viewpager.getDeclaredField("mPopulatePending");
mPopulatePending.setAccessible(true);
mPopulatePending.set(this, false);
Method setCurrentItemInternal = viewpager.getDeclaredMethod("setCurrentItemInternal", int.class, boolean.class, boolean.class, int.class);
setCurrentItemInternal.setAccessible(true);
setCurrentItemInternal.invoke(this, item, smoothScroll, false, velocity);
} catch (Exception e) {
e.printStackTrace();
}
}
}
回答by iTurki
The ViewPager was changed a lotfrom revision 5 to 9. Some of those changes that might be related to your problem:
ViewPager从第 5 版到第 9 版发生了很大变化。其中一些可能与您的问题有关的更改:
- Bug fixes for user interface behavior in ViewPager (revision 5 and 6)
- Fixed numerous bugs for ViewPager (revision 9)
- ViewPager 中用户界面行为的错误修复(修订版 5 和 6)
- 修复了 ViewPager(修订版 9)的许多错误
Giving that your code is supposed to work just fine, my best guess is that your support library is not up-to-date. Try updating the library if it isn't.
鉴于您的代码应该可以正常工作,我最好的猜测是您的支持库不是最新的。如果不是,请尝试更新库。
回答by Dron
I had the same problem, but today I've found a simple solution. Maybe it will help you. First, lets suppose we have a ViewPager that filled the whole screen. To switch between pages I've created my own custom View with tabs and put it over the ViewPager. Clicking a tab should scroll smoothly to the appropriate page in ViewPager with setCurrentItem(item, true) - but it scrolls instantly, with no smooth! Then I tried to add a simple button (not custom) over the ViewPager + callback:
我遇到了同样的问题,但今天我找到了一个简单的解决方案。也许它会帮助你。首先,假设我们有一个填充整个屏幕的 ViewPager。为了在页面之间切换,我创建了自己的带有选项卡的自定义视图并将其放在 ViewPager 上。单击选项卡应该使用 setCurrentItem(item, true) 平滑滚动到 ViewPager 中的相应页面 - 但它会立即滚动,没有平滑!然后我尝试在 ViewPager + 回调上添加一个简单的按钮(非自定义):
@Override
public void onClick(View v) {
viewPager.setCurrentItem(item, true);
}
After that the smooth scroll stared working. So, the solution was very simple: inside the Button class the internal boolean onTouch(...) listener returns true, so it always CONSUMES touch events! Then the smooth scroll started working for my custom tabs view when I substitued "return false" with "return true" in the internal boolean onTouch(...) listener.
之后,平滑滚动开始工作。因此,解决方案非常简单:在 Button 类中,内部布尔值 onTouch(...) 侦听器返回 true,因此它始终消耗触摸事件!然后,当我在内部布尔值 onTouch(...) 侦听器中用“return true”替换“return false”时,平滑滚动开始为我的自定义选项卡视图工作。
I hope my success story can help you.
我希望我的成功故事可以帮助到你。
回答by Mikhail
For those who use Xamarin (albeit this approach is applicable to Java as well) I can suggest to use the next approach based on the answer above (ViewPager from Android Support Library v7 AppCompat 19.1.0):
对于那些使用 Xamarin 的人(尽管这种方法也适用于 Java),我可以建议使用基于上述答案的下一种方法(Android 支持库 v7 AppCompat 19.1.0 中的 ViewPager):
public void ScrollSmooth(int i)
{
var jClass = JNIEnv.GetObjectClass(_pager.Handle);
var jMethod = JNIEnv.GetMethodID(jClass, "setCurrentItemInternal", "(IZZI)V");
JNIEnv.CallVoidMethod (_pager.Handle, jMethod, new JValue (i), new JValue (true), new JValue (false), new JValue (1));
}
It relies on ViewPager implementation from http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/support/v4/view/ViewPager.java
它依赖于http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/support/v4/view/ViewPager.java 中的ViewPager 实现
回答by Anil Jaiswal
After wasting my whole day I found a solution set offscreenPageLimit to total no. of the page.
在浪费了我一整天之后,我找到了一个解决方案,将 offscreenPageLimit 设置为 no。页面的。
please follow this https://stackoverflow.com/a/54800154/9097612
回答by u11454072
Note this variable mFirstLayout
-
it will be set true while viewpager callback onAttachedToWindow
(such as on recyclerview),so will be not smoothScroll. You should override onAttachedToWindow to control the mFirstLayout
variable. Something like this:
注意这个变量mFirstLayout
——在viewpager回调时onAttachedToWindow
(比如recyclerview)会被设置为true ,所以不会smoothScroll。您应该覆盖 onAttachedToWindow 来控制mFirstLayout
变量。像这样:
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
try {
Field mFirstLayout = ViewPager.class.getDeclaredField("mFirstLayout");
mFirstLayout.setAccessible(true);
mFirstLayout.set(this, false);
getAdapter().notifyDataSetChanged();
setCurrentItem(getCurrentItem());
} catch (Exception e) {
e.printStackTrace();
}
}