解决ViewPager setCurrentItem 时闪太快
gpyq6055
8年前
<p>ViewPager 使用 setCurrentItem 的时候,如果两个页面相聚比较远,比如从第一个页面跳到第六个页面,就会闪一下,解决办法就是把界面滑动的效果的 duration 设置为0,但是ViewPager 内部的 mScroller 无法正常获得,所以可以尝试采用 反射的方法:</p> <h2><strong>先自定一个MScroller</strong></h2> <p>方便调节 duration</p> <pre> <code class="language-java">public class MScroller extends Scroller { private static final Interpolator sInterpolator = new Interpolator() { public float getInterpolation(float t) { t -= 1.0f; return t * t * t * t * t + 1.0f; } }; public boolean noDuration; public void setNoDuration(boolean noDuration) { this.noDuration = noDuration; } public MScroller(Context context) { this(context,sInterpolator); } public MScroller(Context context, Interpolator interpolator) { super(context, interpolator); } @Override public void startScroll(int startX, int startY, int dx, int dy, int duration) { if(noDuration) //界面滑动不需要时间间隔 super.startScroll(startX, startY, dx, dy, 0); else super.startScroll(startX, startY, dx, dy,duration); } }</code></pre> <h2><strong>定义一个辅助类</strong></h2> <pre> <code class="language-java">public class ViewPageHelper { ViewPager viewPager; MScroller scroller; public ViewPageHelper(ViewPager viewPager) { this.viewPager = viewPager; init(); } public void setCurrentItem(int item){ setCurrentItem(item,true); } public MScroller getScroller() { return scroller; } public void setCurrentItem(int item, boolean somoth){ int current=viewPager.getCurrentItem(); //如果页面相隔大于1,就设置页面切换的动画的时间为0 if(Math.abs(current-item)>1){ scroller.setNoDuration(true); viewPager.setCurrentItem(item,somoth); scroller.setNoDuration(false); }else{ scroller.setNoDuration(false); viewPager.setCurrentItem(item,somoth); } } private void init(){ scroller=new MScroller(viewPager.getContext()); Class<ViewPager>cl=ViewPager.class; try { Field field=cl.getDeclaredField("mScroller"); field.setAccessible(true); //利用反射设置mScroller域为自己定义的MScroller field.set(viewPager,scroller); } catch (NoSuchFieldException e) { e.printStackTrace(); }catch (IllegalAccessException e){ e.printStackTrace(); } } }</code></pre> <p>这样每次设置页面的时候,通过 helper 就可以自动选择是否有时间间隔了。</p> <p>但是这样有点麻烦,每次还要手动改,而且使用TabLayout的话,它会自动调用ViewPager的方法,无法使用Helper,所以可以采用自定一个一个 ViewPager</p> <pre> <code class="language-java">public class SuperViewPager extends ViewPager { private ViewPageHelper helper; public SuperViewPager(Context context) { this(context,null); } public SuperViewPager(Context context, AttributeSet attrs) { super(context, attrs); helper=new ViewPageHelper(this); } @Override public void setCurrentItem(int item) { setCurrentItem(item,true); } @Override public void setCurrentItem(int item, boolean smoothScroll) { MScroller scroller=helper.getScroller(); if(Math.abs(getCurrentItem()-item)>1){ scroller.setNoDuration(true); super.setCurrentItem(item, smoothScroll); scroller.setNoDuration(false); }else{ scroller.setNoDuration(false); super.setCurrentItem(item, smoothScroll); } } }</code></pre> <p>这样用起来就很方便了。</p> <h3><strong>fragment布局</strong></h3> <pre> <code class="language-java"><?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:background="@color/colorPrimary" android:layout_height="match_parent"> <TextView android:gravity="center" android:textSize="27sp" android:textColor="#ffffff" android:layout_centerInParent="true" android:id="@+id/textview" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout></code></pre> <h3><strong>MFragment</strong></h3> <pre> <code class="language-java">public class MFragemnt extends Fragment { private String name="default"; public static MFragemnt newInstance(String name){ MFragemnt fragemnt=new MFragemnt(); fragemnt.name=name; return fragemnt; } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view=inflater.inflate(R.layout.fragment_test,container,false); TextView textView=(TextView)view.findViewById(R.id.textview); textView.setText(name); return view; } }</code></pre> <h3><strong>activity 布局</strong></h3> <pre> <code class="language-java"><?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingTop="@dimen/activity_vertical_margin" tools:context="thereisnospon.viewpager.MainActivity"> <android.support.design.widget.TabLayout android:id="@+id/tablayout" android:layout_width="match_parent" android:layout_height="wrap_content"></android.support.design.widget.TabLayout> <thereisnospon.viewpager.SuperViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent"></thereisnospon.viewpager.SuperViewPager> </LinearLayout></code></pre> <p>这里使用了一个 tabLayout ,它是在 design 包里的</p> <p>需要在 gradle 文件加:</p> <pre> <code class="language-java">compile 'com.android.support:design:23.4.0'</code></pre> <h3>activity</h3> <pre> <code class="language-java">public class MainActivity extends AppCompatActivity { private TabLayout tablayout; private SuperViewPager viewPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); this.viewPager = (SuperViewPager) findViewById(R.id.viewPager); this.tablayout = (TabLayout) findViewById(R.id.tablayout); viewPager.setAdapter(new PageAdapter(getSupportFragmentManager())); tablayout.setupWithViewPager(viewPager); } public static class PageAdapter extends FragmentPagerAdapter{ public PageAdapter(FragmentManager fm) { super(fm); } @Override public CharSequence getPageTitle(int position) { return "P:"+position; } @Override public Fragment getItem(int position) { return MFragemnt.newInstance("Page:"+position); } @Override public int getCount() { return 5; } } }</code></pre> <p> </p> <p>来自:http://www.jianshu.com/p/ae360ffcbcda</p> <p> </p>