Android ViewPager setCurrentItem(pageId,true)无法平滑滚动
我在SDK 4.03、Samsung Infuse Android 2.2、Android 4支持库上编译,并在我的应用程序中使用ViewPager,实际的滑动效果很好,但当我这样做的时候Android ViewPager setCurrentItem(pageId,true)无法平滑滚动,android,android-layout,Android,Android Layout,我在SDK 4.03、Samsung Infuse Android 2.2、Android 4支持库上编译,并在我的应用程序中使用ViewPager,实际的滑动效果很好,但当我这样做的时候 viewPager.setCurrentItem(id); // , or viewPager.setCurrentItem(id, true); 它不会平滑滚动,但会立即切换视图。尽管文档清楚地说明了这是将第二个参数设置为true的目的。这是怎么回事?ViewPager从第5版更改为第9版。其中一些更
viewPager.setCurrentItem(id); // , or
viewPager.setCurrentItem(id, true);
它不会平滑滚动,但会立即切换视图。尽管文档清楚地说明了这是将第二个参数设置为true的目的。这是怎么回事?ViewPager从第5版更改为第9版。其中一些更改可能与您的问题有关:
- ViewPager中用户界面行为的错误修复(第5版和第6版)
- 修复了ViewPager(修订版9)的许多错误
考虑到您的代码应该工作正常,我最好的猜测是您的支持库不是最新的。如果没有,请尝试更新库。我也有同样的问题,但今天我找到了一个简单的解决方案。也许对你有帮助。 首先,假设我们有一个ViewPager,它占据了整个屏幕。为了在页面之间切换,我创建了自己的带有选项卡的自定义视图,并将其置于ViewPager上。单击选项卡应使用setCurrentItem(item,true)平滑地滚动到ViewPager中的相应页面,但它会立即滚动,不会平滑!然后我尝试在ViewPager+回调上添加一个简单的按钮(非自定义):
@Override
public void onClick(View v) {
viewPager.setCurrentItem(item, true);
}
之后,平滑的卷轴开始工作。因此,解决方案非常简单:在Button类中,内部布尔onTouch(…)侦听器返回true,因此它总是使用触摸事件!然后,当我在内部布尔onTouch(…)侦听器中将“return false”替换为“return true”时,平滑滚动开始用于我的自定义选项卡视图
我希望我的成功故事能对你有所帮助。这就是我所做的。我在
ViewPager
中将自己的自定义子类放在同一个包中,从而覆盖了包私有方法smoothScrollTo
。传递给它的值为零,这将导致捕捉行为而不是平滑滚动
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);
}
}
它工作得很好,如果您愿意,您可以计算并提供实际速度ISO,仅为1。我通过创建MyViewPager,使用反射覆盖ViewPager.mScroller,解决了这个问题
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*/);
}
}
}
公共类MyViewPager扩展了ViewPager{
公共MyViewPager(上下文、属性集属性){
超级(上下文,attrs);
setMyScroller();
}
私有void setMyScroller(){
试一试{
Class viewpager=viewpager.Class;
字段滚动器=viewpager.getDeclaredField(“mScroller”);
scroller.setAccessible(true);
set(这是新的MyScroller(getContext());
}捕获(例外e){
e、 printStackTrace();
}
}
公共类MyScroller扩展了Scroller{
公共MyScroller(上下文){
super(上下文,新减速器插值器());
}
@凌驾
公共无效开始滚动(int startX、int startY、int dx、int dy、int duration){
超级startScroll(startX,startY,dx,dy,1000/*1秒*/);
}
}
}
对于那些使用Xamarin的人(尽管这种方法也适用于Java),我可以根据上面的答案建议使用下一种方法(来自Android支持库v7 AppCompat 19.1.0的ViewPager):
它依赖于来自的ViewPager实现,我知道这个线程很旧,但这是谷歌的顶级结果之一。我已经反复讨论如何解决这个问题很久了。以上所有的解决方案都对我毫无帮助。然而,我确实找到了一个适合我的解决方案 我的设置当前看起来像是viewpager中的listview。当您单击其中一个视图时,它将创建一个新页面并滚动到该页面。这是非常快之前,但似乎这是因为我打电话
mViewPager.setCurrentItem(intIndex, true);
从我的事件内部。由于某些原因,viewpager不喜欢此功能,因此我创建了此功能。它创建一个新线程,在UI线程上运行runnable。此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();
}
publicstaticvoidscrolltoindex(int索引){
最终int intIndex=索引;
//我们要做另一条线,把我们自己和任何东西分开
//我们在哪
Thread sepThread=新线程(new Runnable(){
公开募捐
{
//然后,在该线程内,在ui线程上运行runnable。
//getContext()是一个静态函数,返回
//活动的上下文。它在必要时很有用。
((活动)MyActivity.getContext()).runOnUiThread(新的Runnable()){
@凌驾
公开募捐{
if(mSlidingTabLayout!=null)
{
//我也用了一个标签带,确保
//tabstrip已更新,否则将无法滚动
//正确地
if(mSlidingTabLayout.getTabStripChildCount()我在处理程序中调用了setCurrentItem
函数,它对我来说运行良好
new Handler().post(new Runnable() {
@Override
public void run() {
myViewPager.setCurrentItem(1, true);
}
});
希望这有帮助。尝试使用以下代码:
viewPager.postDelayed(new Runnable()
{
@Override
public void run()
{
viewPager.setCurrentItem(id, true);
}
}, 100);
我创建这个类是因为我对上述解决方案不完全满意
该类重写setCurrentItem(int-item,boolean smoothScroll)
,并使用反射尽可能保持此方法的原始性。关键是速度不是0。
您只需将当前的ViewPager
替换为该MyViewPager
类,并像正常情况一样使用它:
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();
}
}
}
导入android.content.Context;
导入android.util.AttributeSet;
导入java.lang.reflect.Field;
导入java.lang.reflect.Method;
导入androidx.viewpager.widget.viewpager;
公共类MyViewPager扩展了ViewPager{
公共MyViewPager(上下文、属性集属性){
超级(上下文,attrs);
}
/**
*设置当前选定的pag
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();
}
}
}
@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();
}
}
import androidx.viewpager.widget.ViewPager;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
viewPager.setCurrentItem(index, true);
}
}, 500);
pager.post {
pager.setCurrentItem(1, true)
}