ViewPager是我们比较熟悉的一个控件,用于视图切换或作为首页的切换,默认是没有动画切换效果的,当然我们可以通过setPageTransform来添加各种各样的动画,这里我们介绍另外一种方法,自定义自带动画切换效果的ViewPager。
首先分析我们要实现动画切换效果,我们必须要准备的工作:
1.首先必须获取两个切换的视图,mLeftView 和 mRightView。
2.然后还必须有一个变化的梯度值,用于控制切换过程中的值变化。
新建一个类 ViewPagerWithTransformAnim.java 继承自ViewPager
public class ViewPageWithTransformAnim extends ViewPager{
//两个View
private View mLeft;
private View mRight;
//变化的梯度
private float mTrans;
//缩放的值
private float mScale;
//缩放的最小值,从0.5 到 1
private static final float MIN_SCALE = 0.5f;
public ViewPageWithTransformAnim(Context context) {
super(context);
}
public ViewPageWithTransformAnim(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onPageScrolled(int position, float offset, int pix) {
Log.i("meng.li", "position = "+position +" offset = "+offset+" pix = "+pix);
super.onPageScrolled(position, offset, pix);
}
}
ViewPager中有一个onPageScrolled方法,我们可以在这里获取我们需要的东西。
我们观察onPageScrolled方法的log信息:
从第0页滑动到第1页
从第1页回到第0页
总结下规律
0页到1页 position 0 ; offset 0-1
1页到0页 position 0 ; offset 1-0
下面仔细研究下这几个参数:
直接说测试结果:
在非第一页与最后一页时,滑动到下一页,position为当前页位置;滑动到上一页:position为当前页-1
positionOffset 滑动到下一页,[0,1)区间上变化;滑动到上一页:(1,0]区间上变化
positionOffsetPixels这个和positionOffset很像:滑动到下一页,[0,宽度)区间上变化;滑动到上一页:(宽度,0]区间上变化
第一页时:滑动到上一页position=0 ,其他基本为0 ;最后一页滑动到下一页 position为当前页位置,其他两个参数为0
豁然发现,我们需要的步骤的第二步解决了,positionOffset很适合作为,渐变,缩放的控制参数;positionOffsetPixels则可以作为平移等的控制参数。
那么如何获得当前View和目的View呢:
分享几个我的歧途:
1、【错误】我通过getChildAt(position),getChildAt(position+1),getChildAt(position-1)获得滑动时,左右的两个View;乍一看,还真觉得不错~~~在代码写出来,再乍效果也出不来~~错误原因:我们忽略一个特别大的东西,ViewPager的机制,滑动时动态加载和删除View,ViewPager其实只会维持2到3个View,而position的范围基本属于无限~~
2、【错误】我通过getCurrentItem获得当前的位置,然后+1,-1获得后一个或者前一个~~正在窃喜,赶快代码改过来,效果怎么也不对,乱七八糟的~~仔细观察日志,这个getCurrentItem当用户手指离开的屏幕,Page还在动画执行时,就改变了~~难怪~整个滑动过程并不是固定的~~唉,心都碎了~
3、【错误】position在整个滑动的过程中是不变化的,而且ViewPager会保存2个或3个View;那么我考虑,如果是第一页、或者最后一页那么我取getChildAt(0)和getChildAt(1),如果在其他页面则为getChildAt(0),getChildAt(2),然后经过一系列的变化~我想这会总该对了吧,于是我遇到第一问题,第一页的时候,不管左右position都为0,尼玛,这哪个为左View,哪个为右View~~
说了这么多错误,大家可以绕过这些弯路,也能从这些弯路里面看出点什么
说了这么多错误,大家可以绕过这些弯路,也能从这些弯路里面看出点什么~
下面说正确的,其实ViewPager在添加一个View或者销毁一个View时,是我们自己的PageAdapter中控制的,于是我们可以在ViewPager里面维系一个HashMap
那么滑到下一页:左边的View:map.get(position) ,右边的View : map.get(position+1) .
那么滑到上一页:左边的View : map.get(position) , 右边的View : map.get(position+1) , 一样的,因为滑到上一页,position为当前页-1
好了,至此,我们分析了且解决了所有步骤
代码: MainActivity.java
public class MainActivity extends Activity {
// private ViewPager viewPager;
//这里是为了兼容3.0版本下设置动画效果从新改写的ViewPager
// private ViewPagerCompat viewPager;
//自定义带动画切换效果的ViewPager
private ViewPageWithTransformAnim viewPager;
private int[] mImgId = new int[]{R.drawable.guide_image1,R.drawable.guide_image2,R.drawable.guide_image3};
List mImages = new ArrayList();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPageWithTransformAnim)findViewById(R.id.view_pager);
viewPager.setAdapter(new PagerAdapter() {
//实例化 Item 创建ImageView
@Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView imageView = new ImageView(MainActivity.this);
imageView.setImageResource(mImgId[position]);
imageView.setScaleType(ScaleType.CENTER_CROP);
container.addView(imageView);
mImages.add(imageView);
//添加到View中
viewPager.setViewForPosition(imageView,position);
return imageView;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
//判断view是否来自于 arg1 arg1 是初始化的时候添加进去的
return arg0 == arg1;
}
@Override
public int getCount() {
//获取视图的长度
return mImgId.length;
}
@Override
public void destroyItem(ViewGroup container, int position,
Object object) {
//移除视图
viewPager.removeViewFromPosition(position);
//移除视图
container.removeView(mImages.get(position));
}
});
}
}
这个很常见的代码,就是初始化ViewPager~~就没啥可说的了~~有一点需要注意:在instantiateItem方法,我们多调用了一个mViewPager.setObjectForPosition(imageView, position);其实就是为了给我们的Map存值
自定义ViewPager
/*
* 自定义的带动画切换效果的ViewPager
*/
/*需要有哪些准备
* a.需要拿到当前切换的两个 View
* b.需要拿到一个动画的梯度值
* Translation 和 Scale
*/
public class ViewPageWithTransformAnim extends ViewPager{
private Map vChildren= new HashMap();
public void setViewForPosition(View view,int position){
vChildren.put(position, view);
}
public void removeViewFromPosition(int position){
vChildren.remove(position);
}
//两个View
private View mLeft;
private View mRight;
//变化的梯度
private float mTrans;
//缩放的值
private float mScale;
//缩放的最小值,从0.5 到 1
private static final float MIN_SCALE = 0.5f;
public ViewPageWithTransformAnim(Context context) {
super(context);
}
public ViewPageWithTransformAnim(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onPageScrolled(int position, float offset, int pix) {
// Log.i("meng.li", "position = "+position +" offset = "+offset+" pix = "+pix);
mLeft = vChildren.get(position);
mRight = vChildren.get(position+1);
//添加动画效果
animStack(mLeft,mRight,offset,pix);
Log.i("meng.li", getCurrentItem() +" -- "+getChildCount());
super.onPageScrolled(position, offset, pix);
}
private void animStack(View left,View right,float offset,int offsetPixels){
if(right != null){
//从0页到1页, offset: 0-1
//从0 逐渐变到1
mScale = (1 - MIN_SCALE)* offset + MIN_SCALE;
//从 0 到宽度的变化
mTrans = -getWidth() -getPageMargin() + offsetPixels;
ViewHelper.setScaleX(right, mScale);
ViewHelper.setScaleY(right, mScale);
ViewHelper.setTranslationX(right, mTrans);
}
if(left != null){
//让其保持在顶部绘制
left.bringToFront();
}
}
}
可以看到,核心代码都是onPageScrolled,我们通过findViewFromObject(position); findViewFromObject(position + 1);分别获取了左右两边的View,然后添加动画效果;当前这个例子添加了两个动画,一个是从0.5放大到1.0或者1.0缩小到0.5,没错由我们的positionOffset提供梯度的变化~~还有个平移的动画:下一页直接移动到当前屏幕(默认是在右边,可以注释这个效果,怎么运行看看),然后不断的通过positionOffsetPixels抵消原来默认移动时的位移,让用户感觉它就在原地放大缩小~~
实现的效果为:
4、JazzyViewPager的使用
其实上面的实现就是github上JazzyViewPager的源码,用法不用说了,就是我们的MainActivity,它内置了大概10来种效果,我们可以通过代码或者布局上面设置动画效果~~我们上面的例子效果,它叫做Stack;
使用JazzViewPager的代码:其实基本一样~~最后也会贴上JazzyViewPager的源码的下载
MainActivity
package com.jfeinstein.jazzyviewpager;
import com.jfeinstein.jazzyviewpager.JazzyViewPager.TransitionEffect;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
public class MainActivity extends Activity
{
protected static final String TAG = "MainActivity";
private int[] mImgIds;
private JazzyViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImgIds = new int[] { R.drawable.a, R.drawable.b, R.drawable.c,
R.drawable.d };
mViewPager = (JazzyViewPager) findViewById(R.id.id_viewPager);
//设置切换效果
mViewPager.setTransitionEffect(TransitionEffect.Stack);
mViewPager.setAdapter(new PagerAdapter()
{
@Override
public boolean isViewFromObject(View arg0, Object arg1)
{
return arg0 == arg1;
}
@Override
public void destroyItem(ViewGroup container, int position,
Object object)
{
container.removeView((View) object);
}
@Override
public Object instantiateItem(ViewGroup container, int position)
{
ImageView imageView = new ImageView(MainActivity.this);
imageView.setImageResource(mImgIds[position]);
imageView.setScaleType(ScaleType.CENTER_CROP);
container.addView(imageView);
mViewPager.setObjectForPosition(imageView, position);
return imageView;
}
@Override
public int getCount()
{
return mImgIds.length;
}
});
}
}
与我们的代码唯一区别就是:
JazzyViewPager 下载地址:https://github.com/jfeinstein10/JazzyViewPager
本文转载自:http://blog.csdn.net/lmj623565791/article/details/38026503