源码分析相关面试题

Activity相关面试题

与XMPP相关面试题

与性能优化相关面试题

与登录相关面试题

与开发相关面试题

与人事相关面试题

本文配套视频

今天做项目用ViewPager.setCurrentItem 方法,如果两个页面相聚比较远,就会闪瞎我的钛合金双眼,中间切换大概20个页面,如下所示:

img

setCurrentItem第二个参数设置false,四不四很简单,直接使用如下代码:

  1. ViewPager.setCurrentItem(position,false);

很不幸的是,使用上面的代码会出现如下效果,扎心了老铁:

img

从第一题点击切换到第十八题,你会发现页面显示空白,如果从第十个页面切换到第十五个页面没事,平时大家估计没有发现这个bug,一般我们使用ViewPager都是底下5个tab页面,从第一个切换到第五个没事,之前我也以为把第二个参数设置false就行,今天才发现,原来如果当页面比较少的时候,大概十个以内,一般没有问题,如果超过十个页面切换就会出现空白,加载不了数据,扎心了,提出解决方案吧,ViewPager滑动使用的是Scroll,咱们把Scroll的滑动时间duration 设置为0就行。

自定义一个Scroll类,用于控制ViewPager滑动速度:

  1. public class MScroller extends Scroller {
  2. private static final Interpolator sInterpolator = new Interpolator() {
  3. public float getInterpolation(float t) {
  4. t -= 1.0f;
  5. return t * t * t * t * t + 1.0f;
  6. }
  7. };
  8. public boolean noDuration;
  9. public void setNoDuration(boolean noDuration) {
  10. this.noDuration = noDuration;
  11. }
  12. public MScroller(Context context) {
  13. this(context,sInterpolator);
  14. }
  15. public MScroller(Context context, Interpolator interpolator) {
  16. super(context, interpolator);
  17. }
  18. @Override
  19. public void startScroll(int startX, int startY, int dx, int dy, int duration) {
  20. if(noDuration)
  21. //界面滑动不需要时间间隔
  22. super.startScroll(startX, startY, dx, dy, 0);
  23. else
  24. super.startScroll(startX, startY, dx, dy,duration);
  25. }
  26. }

上面代码可知:

1)动态判断页面是否需要滑动,如果不需要滑动,设置滑动时间为0;

为方便使用,定义一个辅助类

  1. public class ViewPageHelper {
  2. ViewPager viewPager;
  3. MScroller scroller;
  4. public ViewPageHelper(ViewPager viewPager) {
  5. this.viewPager = viewPager;
  6. init();
  7. }
  8. public void setCurrentItem(int item){
  9. setCurrentItem(item,true);
  10. }
  11. public MScroller getScroller() {
  12. return scroller;
  13. }
  14. public void setCurrentItem(int item, boolean somoth){
  15. int current=viewPager.getCurrentItem();
  16. //如果页面相隔大于1,就设置页面切换的动画的时间为0
  17. if(Math.abs(current-item)>1){
  18. scroller.setNoDuration(true);
  19. viewPager.setCurrentItem(item,somoth);
  20. scroller.setNoDuration(false);
  21. }else{
  22. scroller.setNoDuration(false);
  23. viewPager.setCurrentItem(item,somoth);
  24. }
  25. }
  26. private void init(){
  27. scroller=new MScroller(viewPager.getContext());
  28. Class<ViewPager>cl=ViewPager.class;
  29. try {
  30. Field field=cl.getDeclaredField("mScroller");
  31. field.setAccessible(true);
  32. //利用反射设置mScroller域为自己定义的MScroller
  33. field.set(viewPager,scroller);
  34. } catch (NoSuchFieldException e) {
  35. e.printStackTrace();
  36. }catch (IllegalAccessException e){
  37. e.printStackTrace();
  38. }
  39. }
  40. }

由上面代码可知:

1)Math.abs(current-item)>1 ,通过数学函数判断页面相隔大于1,就设置页面切换的动画的时间为0。

2)这样每次设置页面的时候,通过 helper 就可以自动选择是否有时间间隔了。

3)但是这样有点麻烦,每次还要手动改,而且使用TabLayout或者ViewPagerIndicator的话,它会自动调用ViewPager的方法,无法使用Helper,所以可以采用自定一个ViewPager,代码如下:

  1. public class SuperViewPager extends ViewPager {
  2. private ViewPageHelper helper;
  3. public SuperViewPager(Context context) {
  4. this(context,null);
  5. }
  6. public SuperViewPager(Context context, AttributeSet attrs) {
  7. super(context, attrs);
  8. helper=new ViewPageHelper(this);
  9. }
  10. @Override
  11. public void setCurrentItem(int item) {
  12. setCurrentItem(item,true);
  13. }
  14. @Override
  15. public void setCurrentItem(int item, boolean smoothScroll) {
  16. MScroller scroller=helper.getScroller();
  17. if(Math.abs(getCurrentItem()-item)>1){
  18. scroller.setNoDuration(true);
  19. super.setCurrentItem(item, smoothScroll);
  20. scroller.setNoDuration(false);
  21. }else{
  22. scroller.setNoDuration(false);
  23. super.setCurrentItem(item, smoothScroll);
  24. }
  25. }
  26. }

至此完美解决了,ViewPager.setCurrentItem切换页面,效果如下:

img

  • 欢迎关注微信公众号,长期推荐技术文章和技术视频
  • 微信公众号名称:Android干货程序员

img