首先我们先展示一个Viewpager的一个Demo
1. 布局文件的编写
<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:background="#000000"
>
<android.support.v4.view.ViewPager
android:id="@+id/id_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
2. Mainactivity的编写
public class MainActivity extends Activity {
private ViewPager viewPager;
private MyAdapter pagerAdapter ;
private int[] mImgIds = new int[]{R.drawable.one,R.drawable.two,R.drawable.three};
private Context mcontext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
mcontext = MainActivity.this;
initView();
}
private void initView() {
// TODO Auto-generated method stub
viewPager = (ViewPager) findViewById(R.id.id_viewpager);
pagerAdapter = new MyAdapter(mcontext, mImgIds);
viewPager.setAdapter(pagerAdapter);
}
}
public class MyAdapter extends PagerAdapter{
private int[] mImgIds;
private Context mcontext;
public MyAdapter(Context mcontext, int[] mImgIds) {
super();
this.mImgIds = mImgIds;
this.mcontext = mcontext;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
// TODO Auto-generated method stub
container.removeView((View) object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
// TODO Auto-generated method stub
ImageView imageView = new ImageView(mcontext);
imageView.setImageResource(mImgIds[position]);
imageView.setScaleType(ScaleType.CENTER_INSIDE);
container.addView(imageView);
return imageView;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO Auto-generated method stub
return arg0 == arg1;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mImgIds.length;
}
}
好的,现在这个代码已经写完了。viewpager里面分别加入了3张图片,切换子view的时候是没有动画效果的。
那么问题来了,如果我们要加入动画,应该需要什么?
1. 因为动画效果是根据我们手势操作来动的,所以我们要监听用户的手势。那么viewpager提供这样的方法呢?有的,就是一个叫做发现了一个叫做
onPageScrolled(int position, float positionOffset, int positionOffsetPixels)的方法
仔细研究下这几个参数
position 表示 当前viewpager处于第几页,positionOffset 就是表示这个pager的偏移的值,这个值是跟随我们的手势不断变化的
从第0页切换到第1页,就是向左边滑动的时候,我们打印一下这个参数看下变化
说白了,
就是像右边滑动,positionOffset的变化区间是【0,1】
同样的,我们页打印一下像左边滑动的信息
像左边滑动,positionOffset的变化区间是【1,0】
可是有个问题。在onPageScrolled中我们每次只能拿到一个view的偏移量啊,我们要对2个子view进行动画,必须拿到2个动态变化的偏移量才行
其实android已经提供给我们这个方法了,只需要ViewPager.PageTransformer 这个接口就可以了。里面会提供给我们一个
void transformPage(View view, float position) 方法,这个方法中可以同时获取左右2个变化的子view的偏移量的结果
但是这里偏移量有点不同,举个例子
当我们滑动时:会打印出当然ViewPager中存活的每个View以及它们的position的变化
* 比如从第0页滑动到第1页时候,
* 第0页的positon : 【0,-1】
* 第1页的positon : 【-1,0】
* 比如从第0页滑动到第1页时候,
* 第0页的positon : 【0,-1】
* 第1页的positon : 【-1,0】
豁然发现,这个positon非常适合做渐变,缩放等动画效果的控制参数
接下来我们就在void transformPage(View arg0, float arg1) 里面,根据positon的变化区域,为我们的左右2个子view做动画
因为要实现旋转的动画效果,
1. 所以必须给这个旋转动画设置一个梯度,就是一个变化区间,让他能从0度,根据我们的手势,变化到另一个角度
2.必须给这个旋转动画设置一个中定点
这个梯度,我们借助positon来实现就可以了,给他整个数学公司,让他也随着position的变化而变化
float mRot = (ROT_MAX * position);
左边那一页的posiotn是从【0,-1】,那么左边那一页的旋转角度应该是从【0,-20度】
右边那一页的positon是从【1,0】,那么右边那一页的旋转角度应该是从【20,0】
上源代码把
public class pagerAnimation implements ViewPager.PageTransformer {
<span style="white-space:pre"> </span>//动画梯度
<span style="white-space:pre"> </span>private float ROT_MAX = 50;
<span style="white-space:pre"> </span>private float mRot ;
<span style="white-space:pre"> </span>@Override
<span style="white-space:pre"> </span>public void transformPage(View view, float position) {
<span style="white-space:pre"> </span>// TODO Auto-generated method stub
<span style="white-space:pre"> </span> //这个是左边页的动画
if (position < 0)
{
<span style="white-space:pre"> </span>//现在我们要根据这个position来定义我们的每个view的角度变化的梯度
mRot = (ROT_MAX * position); //posiotn是从【0,-1】,所以mRot是从【0,-20度】
//旋转的中心点是哪里?我们把他定义在正下方中间处
view.setPivotX(view.getMeasuredWidth() * 0.5f);
view.setPivotY(view.getMeasuredHeight());
view.setRotation(mRot);
}
//这个是右边页的动画
else if (position > 0)
{
mRot = (ROT_MAX * position); //posiotn是从【1,0】,所以mRot是从【20度到0度】
view.setPivotX(view.getMeasuredWidth() * 0.5f);
view.setPivotY(view.getMeasuredHeight());
view.setRotation(mRot);
}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
}
好的,这样我们的动画就写好了。
别忘了我们还是回到viewpager中,给他设置一下我们定义的这个切换动画
private void initView() {
// TODO Auto-generated method stub
viewPager = (ViewPager) findViewById(R.id.id_viewpager);
pagerAdapter = new MyAdapter(mcontext, mImgIds);
viewPager.setAdapter(pagerAdapter);
viewPager.setPageTransformer(true, new pagerAnimation());
}
具体效果,请参考我们的平板
关于Viewpager的性能优化
如果我们的viewpager中加入了多个view,而且这多个view的布局都非常的深,加载非常多的高清图片,那么我们就会发现,viewpager在切换的时候非常的卡,加上动画就跟卡了,我们可以开启Viewpager的缓存功能来解决他,并且让他加载第0页的pager的同时,就去预加载其他页
<android.support.v4.view.ViewPager
android:id="@+id/id_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:persistentDrawingCache="all"
/>
这里viewpager就会去缓存我们的动画和图片,不再重复的加载(注意,adapter的ondestoryitem方法也要修改,不要再让他销毁之前加载的内容)
代码中我们去开启预加载
private void initView() {
// TODO Auto-generated method stub
viewPager = (ViewPager) findViewById(R.id.id_viewpager);
pagerAdapter = new MyAdapter(mcontext, mImgIds);
viewPager.setOffscreenPageLimit(3);
viewPager.setAdapter(pagerAdapter);
viewPager.setPageTransformer(true, new pagerAnimation());
}
这样加载第0页,就回去预加载另外的2页
这些都是牺牲内存去换取时间的方法,并不好。
最根本的还是要回头解决子view布局过深和加载过多高清大图的问题