1、设置页面是否可以滑动翻页
开发中也需会有这种需求,期望通过切换tab按钮来切换页面,而不是滑动翻页,但是我们又不可能每次点击tab按钮都重新加载一个页面,那效率太低了,因此我们可以
使用ViewPager来帮我们缓存页面。但是ViewPager默认是可以通过手势滑动切换页面的,那么如何禁止手势滑动切换页面呢?
我们可以通过重写onInterceptTouchEvent和onTouchEvent,如果不想滑动翻页,则返回false,不拦截触摸事件。
/**
* 是否可以滑动翻页
*
* @param pagerEnabled
*/
public void setPagingEnabled(boolean pagerEnabled)
{
this.pagerEnabled = pagerEnabled;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (pagerEnabled) {
return super.onTouchEvent(event);
} else {
return false;
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (pagerEnabled) {
return super.onInterceptTouchEvent(event);
} else {
return false;
}
}
2、设置滑动翻页的速度
ViewPager默认的翻页速度比较快,如果想让翻页速度变得平滑一点,那么实现呢?
我们知道ViewPager类中有一个Scroller类型的成员变量,叫mScroller,就是用来控制滑动的。通过调用 mScroller.startScroll(sx, sy, dx, dy, duration)来实现页面滚动。这里
不对Scroller做过多介绍,大家只需知道使用Scroller可以完成页面的滚动就行了,而且系统大部分控件的滚动都是用Scroller来实现的。下面解释一下
mScroller.startScroll(sx, sy, dx, dy, duration) 方法的几个参数:
sx:开始x坐标
sy:开始y坐标
dx:x轴方向滚动的距离,负数向左,正数向右
dy:y轴方向滚动的距离,负数向上,正数向下
duration:滚动的时长
其中控制duration就可以控制滚动时长,ViewPager计算出来的滚动时长是比较短的,所以我们可以看到切换页面时非常快速就闪过了。如果想让页面切换变得平滑一点,
就可以控制duration.那么怎么在ViewPager调用mScroller.startScroll(sx, sy, dx, dy, duration)时改变duration呢,首先duration是ViewPager内部计算的,这个没法去改变,
还有就是可以通过重写startScroll方法。但是mScroller是ViewPager的私有变量,因此我们需要通过java的反射机制,注入我们自己的Scroller。
继承ViewPager,然后在ViewPager的构造函数中,通过反射注入我们自己的Scroller,
try {
Class<?> viewpager = android.support.v4.view.ViewPager.class;
Field scroller = viewpager.getDeclaredField("mScroller");
scroller.setAccessible(true);
Field interpolator = viewpager.getDeclaredField("sInterpolator");
interpolator.setAccessible(true);
mScroller = new CustomDurationScroller(getContext(),
(Interpolator) interpolator.get(null));
scroller.set(this, mScroller);
} catch (Exception e) {
e.printStackTrace();
}
CustomDurationScroller就是我们自定义的Scroller
public class CustomDurationScroller extends Scroller {
private float mScrollFactor = 1.0f;
private float mFactor = mScrollFactor;
public CustomDurationScroller(Context context) {
super(context);
}
public CustomDurationScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
@SuppressLint("NewApi")
public CustomDurationScroller(Context context, Interpolator interpolator, boolean flywheel) {
super(context, interpolator, flywheel);
}
/**
* Set the factor by which the duration will change
*/
public void setScrollDurationFactor(float scrollFactor) {
mFactor = mScrollFactor = scrollFactor;
}
public void resetDurationFactor() {
mFactor = 1.0f;
}
public float getScrollDuraionFactor() {
return mScrollFactor;
}
@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, (int) (duration * mFactor));
}
}
重写startScroll方法,通过设置滑动因子mFactor来改变滑动时长duration。
之后ViewPager调用mScroller的startScroll方法,duration都会改变,从而加快(mFactor>1)或放缓(mFactor<1)滚动速度。
3、一页显示多个item
ViewPager默认一页显示一个item,那么如何在一页显示多个item呢?
4、按照item实际高度动态调整
ViewPager默认会按item中最大的高度来调整自身的高度,比如第一个item的高度是300dp,第二个item的高度是150dp,则ViewPager的高度最后会按照300dp来显示,
导致第二个item的底部会留50dp的空白。那么针对这种item不一样高度的ViewPager,如何按item实际高度来展示呢?
public class WrapContentHeightViewPager extends common.widget.viewpager.ViewPager {
public WrapContentHeightViewPager(Context context) {
super(context);
}
public WrapContentHeightViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = 0;
// 下面遍历所有child的高度
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec,
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
if (h > height) // 采用最大的view的高度。
height = h;
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
在xml中使用
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:clipChildren="false"
android:layerType="software" >
<common.widget.viewpager.WrapContentHeightViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:overScrollMode="never" />
</LinearLayout>
1) clipChildren=false,表示不裁剪ViewPager的绘制区域,利用这个属性可以控制一屏显示多的item。
2) 多个item之间的间隔可以通过viewPager.setPageMargin(margin)设置。
5、打造绚丽切换效果的ViewPager
实现PageTransformer,然后viewPager.setPageTransformer(PageTransformer transformer)来实现ViewPager的页面切换效果,其中属性动画可由
ninooldandroids进行实现。
android官网也提供好了几个写好的PageTransformer供参考。地址 http://developer.android.com/training/animation/screen-slide.html
总结:
1)setPageTransformer在3.0以上才起作用,当然也可以设置代码兼容到3.0以下,但是现在的app最低版本应该都是4.0+了,所以没有多大必要兼容3.0以下了。
2)A页切换到B页
A页的position: 0.0 ~ -1
B页的position: 1 ~ 0.0
public class MyPagerTransformer implements ViewPager.PageTransformer {
@Override
public void transformPage(View page, float position) {
if(position<-1) //[负无穷~-1)
{
}else if(position<=0) //A页 0.0~ -1.0
{ //[-1,0]
}
else if(position<=1)//B页 1.0~0.0
{ //(0,1]
}
else //(1,正无穷]
{
}
}
}
利用这个变化规律,可以计算出我们自己想要的动画梯度值。结合属性动画,动态改变透明度、缩放值、位移、旋转等效果。
6、无限循环的ViewPager
实现ViewPager的无限滑动,有两种解决方案
1)实现一种假的无限循环,取一种最大值的思路,比如Integer.MAX_VALUE,然后将一页的初始位置通过setCurrentItem(position) 定位到 position=Integer.MAX_VALUE/2. 这样向左向右滑动都可以。这种做法一般来说也可以满足需求,因为要切换一个相当大的数才能到达末尾。但是毕竟不是最可靠的解决方案。
2)在存放View的集合中的第一个位置放入真正的最后一个View,而在最后一个放入第一个。具体可参考 http://blog.csdn.net/oweixiao123/article/details/23459041
以上就是ViewPager的一些高级用法,具体用法没有做过多说明,大家开发中有不明白的可百度或google,这里只是做一个用法的汇总,给大家一些思路,希望能帮到大家。