一、概述
JazzViewPager是什么?它其实是一种自定义View,继承ViewPager,普通v4包提供的ViewPager只能完成一些2d,的效果,如果想要完成更加酷的效果肯定需要我们自己设置(动画)。
二、Demo例子
xml文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<com.lw.myviewpager.other.JazzyViewPager
android:id="@+id/jvp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
></com.lw.myviewpager.other.JazzyViewPager>
</RelativeLayout>
java代码:
public class MainActivity extends Activity {
private JazzyViewPager jvp;
private int[] mImageViews = new int[]{
R.drawable.clothing_01,
R.drawable.clothing_02,
R.drawable.clothing_03,
R.drawable.clothing_04,
R.drawable.clothing_05,
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
jvp = (JazzyViewPager) findViewById(R.id.jvp);
jvp.setTransitionEffect(TransitionEffect.CubeOut);
jvp.setAdapter(new MyAdapter());
}
class MyAdapter extends PagerAdapter {
@Override
public int getCount() {
return mImageViews.length;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return object == view;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView img = new ImageView(MainActivity.this);
img.setImageResource(mImageViews[position]);
img.setScaleType(ImageView.ScaleType.CENTER_CROP);
container.addView(img);
jvp.setObjectForPosition(img, position);
return img;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
}
三、Demo + JazzViewPager源码分析:
首先,看这行代码,主要设置一会ViewPager切换时的效果
jvp.setTransitionEffect(TransitionEffect.CubeOut);
public void setTransitionEffect(TransitionEffect effect) {
mEffect = effect;
}
将effect赋值给全局mEffect后,后面会通过switch判断,根据什么效果,开始执行什么动画。
switch (mEffect) {
case Standard:
break;
case Tablet:
animateTablet(mLeft, mRight, effectOffset);
break;
case CubeIn:
animateCube(mLeft, mRight, effectOffset, true);
break;
case CubeOut:
animateCube(mLeft, mRight, effectOffset, false);
break;
case FlipVertical:
animateFlipVertical(mLeft, mRight, positionOffset,
positionOffsetPixels);
break;
case FlipHorizontal:
animateFlipHorizontal(mLeft, mRight, effectOffset,
positionOffsetPixels);
case Stack:
animateStack(mLeft, mRight, effectOffset, positionOffsetPixels);
break;
case ZoomIn:
animateZoom(mLeft, mRight, effectOffset, true);
break;
case ZoomOut:
animateZoom(mLeft, mRight, effectOffset, false);
break;
case RotateUp:
animateRotate(mLeft, mRight, effectOffset, true);
break;
case RotateDown:
animateRotate(mLeft, mRight, effectOffset, false);
break;
case Accordion:
animateAccordion(mLeft, mRight, effectOffset);
break;
}
接着,当我们横向移动Viewpager的时候,会触发onPageScrolled(int position, float positionOffset,
int positionOffsetPixels)方法,这三个参数比较简单,自行打印log即可明白,在JazzViewPager的onPageScrolled中有两行比较重要的代码,如下,获取左右两边的View,
mLeft = findViewFromObject(position);
mRight = findViewFromObject(position + 1);
点进去,看源码:
public View findViewFromObject(int position) {
Object o = mObjs.get(Integer.valueOf(position));
if (o == null) {
return null;
}
PagerAdapter a = getAdapter();
View v;
for (int i = 0; i < getChildCount(); i++) {
v = getChildAt(i);
if (a.isViewFromObject(v, o))
return v;
}
return null;
}
private HashMap<Integer, Object> mObjs = new LinkedHashMap<Integer, Object>();
从源码中可以看出s首先根据position从一个增删快的map集合中获取一个object对象,那么这个object到底是什么类型,又是什么时候初始化数据的呢?再回到例子中MyAdapter中的instantiateItem方法,其中有一个代码如下:
jvp.setObjectForPosition(img, position);
其中img为图片ImageView对象,点进去看源码:
public void setObjectForPosition(Object obj, int position) {
mObjs.put(Integer.valueOf(position), obj);
}
由此可以看出这个mObj是在这个时候进行初始化数据的。也就是说map集合里面保存的其实是每一个ImageView和对应position对应关系。再回到JazzViewPager的findViewFromObject()方法,从集合中取出object对象,判断是否为null,如果为null直接返回,否则依次遍历ViewPager子item,调用ViewPager的isViewFromObject方法判断是否为true,是返回v。就这样获取了当在左右移动时滑动的左右子view,接着就是根据之前传递过来的mEffect
进行动画了。如下:
private void animateCube(View left, View right, float positionOffset,
boolean in) {
if (mState != State.IDLE) {
if (left != null) {
mRot = (in ? 90.0f : -90.0f) * positionOffset;
//设置旋转中心点
ViewHelper.setPivotX(left, left.getMeasuredWidth());
ViewHelper.setPivotY(left, left.getMeasuredHeight() * 0.5f);
//设置旋转角度
ViewHelper.setRotationY(left, mRot);
}
if (right != null) {
mRot = -(in ? 90.0f : -90.0f) * (1 - positionOffset);
ViewHelper.setPivotX(right, 0);
ViewHelper.setPivotY(right, right.getMeasuredHeight() * 0.5f);
ViewHelper.setRotationY(right, mRot);
}
}
}
判断左右子view是否为null,只有在不为null的条件下才会进动画。动画的执行比较简单,mRot是根据左右移动的便宜量来计算的。注意:这里的要用到ViewHelper需要导入nineoldandroids.jar包。
四、总结
JazzViewPager最终主要是根据属性动画来完成各种酷炫的效果的,过程中使用map来维持了Object和position的关系,在初始化的时候就在map集合中存入,由于ViewPager的懒加载机制,默认会加载下一页数据,因此left和right都有值。