(在本文中引用到了hyman大神的文章,在此感谢hyman大神的无私奉献,为开源致敬!为技术分享致敬!)
先看看viewpager的API开发详解
英文版:http://www.android-doc.com/reference/android/support/v4/view/ViewPager.html
自己的翻译:
Layout manager that allows the user to flip left and right through pages of data. You supply an implementation of a PagerAdapter
to generate the pages that the view shows.
布局管理器允许使用者使用翻转的形式去展示数据(通过一页接着一页),你需要提供一个继承了PagerAdapter的类去生成这些需要用view去展示的翻转的页。
Note this class is currently under early design and development. The API will likely change in later updates of the compatibility library, requiring changes to the source code of apps when they are compiled against the newer version.
注意:这个类是早期设计和研发的,在以后的API可能发生变化。
ViewPager is most often used in conjunction with Fragment
, which is a convenient way to supply and manage the lifecycle of each page. There are standard adapters implemented for using fragments with the ViewPager, which cover the most common use cases. These are FragmentPagerAdapter
and FragmentStatePagerAdapter
; each of these classes have simple code showing how to build a full user interface with them.
ViewPager是经常与Fragment相互协调共同使用的,哪个是方便的方式去提供和管理这些page的生命周期。这里有两个标准的适配器以供Viewpger与Fragment之间结合的使用。他们是FragmentPagerAdapter和FragmentStatePagerAdapter。
这两个类都有简单的代码示例去展示如何构建一个用户界面
Here is a more complicated example of ViewPager, using it in conjuction with ActionBar
tabs. You can find other examples of using ViewPager in the API 4+ Support Demos and API 13+ Support Demos sample code.
这里就不全翻译了。下面是一个例子的使用(Viewpager+ActionBar)当然这个你可以去到上面给到的网站去浏览。
总结:通过上面我们可以总结出以下几点
1:需要提供一个实现了PageraAdapter的类
2:这个类是实时变化的,需要密切关注
3:有两个很便捷的adapter以供viewpager与fragemnt结合使用时使用。他们是FragmentPagerAdapter和FragmentStatePagerAdapter
以下是转载自大神HYMAN的一篇文章,觉得非常好,已经把我想写的给写出来,有时间了自己写一篇~ 希望能帮到在了解ViewPager的大家,在自定义动画的时候,有几个知识点需要了解到:
从Android3.1开始,View新增了如下方法:
setsetAlpha:透明度变化;
setTranslation:位置变化;
setScale:缩放变化;
setRotation:角度变化;
我们可以用这些方法的组合来实现各种View切换特效;
------------------------------------分割线----------------代码实现DEMO----------------------------------------------------------
1、概述
本篇博文,将:
1、介绍如何使用setPageTransformer设置切换动画;
2、自定义PageTransformer实现个性的切换动画;
3、该方法在SDK11以下的版本不起作用,我们会对其做一定修改,让其向下兼容。
官方示例地址:http://developer.android.com/training/animation/screen-slide.html 有兴趣的可以去看看~~
好了,下面开始编写代码~~
2、setPageTransformer的使用
首先我们迅速的实现一个传统的ViewPager效果~
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.support.v4.view.ViewPager
- android:id="@+id/id_viewpager"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent" />
-
- </RelativeLayout>
2、MainActivity
- package com.zhy.demo_zhy_08_viewpageranim;
-
- import java.util.ArrayList;
- import java.util.List;
-
- import android.app.Activity;
- import android.os.Bundle;
- import android.support.v4.view.PagerAdapter;
- import android.support.v4.view.ViewPager;
- import android.view.View;
- import android.view.ViewGroup;
- import android.view.Window;
- import android.widget.ImageView;
- import android.widget.ImageView.ScaleType;
-
- public class MainActivity extends Activity
- {
- private ViewPager mViewPager;
- private int[] mImgIds = new int[] { R.drawable.guide_image1,
- R.drawable.guide_image2, R.drawable.guide_image3 };
- private List<ImageView> mImageViews = new ArrayList<ImageView>();
-
- @Override
- protected void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.activity_main);
-
- initData();
-
- mViewPager = (ViewPager) findViewById(R.id.id_viewpager);
-
- mViewPager.setAdapter(new PagerAdapter()
- {
- @Override
- public Object instantiateItem(ViewGroup container, int position)
- {
-
- container.addView(mImageViews.get(position));
- return mImageViews.get(position);
- }
-
- @Override
- public void destroyItem(ViewGroup container, int position,
- Object object)
- {
-
- container.removeView(mImageViews.get(position));
- }
-
- @Override
- public boolean isViewFromObject(View view, Object object)
- {
- return view == object;
- }
-
- @Override
- public int getCount()
- {
- return mImgIds.length;
- }
- });
-
- }
-
- private void initData()
- {
- for (int imgId : mImgIds)
- {
- ImageView imageView = new ImageView(getApplicationContext());
- imageView.setScaleType(ScaleType.CENTER_CROP);
- imageView.setImageResource(imgId);
- mImageViews.add(imageView);
- }
- }
-
- }
好了,这样一个传统ViewPager就实现了~~大家对上面代码应该不会有任何陌生的感觉~运行效果也不用贴图了,大家肯定知道~~
3、PageTransformer
ViewPager有个方法叫做:
setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) 用于设置ViewPager切换时的动画效果,并且google官方还给出了两个示例。
只需要在上述代码中调用setPageTransformer即可添加切换动画效果~~下面演示google的两个PageTransformer的代码,以及运行效果。
1、DepthPageTransformer
- public class DepthPageTransformer implements ViewPager.PageTransformer {
- private static final float MIN_SCALE = 0.75f;
-
- public void transformPage(View view, float position) {
- int pageWidth = view.getWidth();
-
- if (position < -1) {
-
- view.setAlpha(0);
-
- } else if (position <= 0) {
-
- view.setAlpha(1);
- view.setTranslationX(0);
- view.setScaleX(1);
- view.setScaleY(1);
-
- } else if (position <= 1) {
-
- view.setAlpha(1 - position);
-
-
- view.setTranslationX(pageWidth * -position);
-
-
- float scaleFactor = MIN_SCALE
- + (1 - MIN_SCALE) * (1 - Math.abs(position));
- view.setScaleX(scaleFactor);
- view.setScaleY(scaleFactor);
-
- } else {
-
- view.setAlpha(0);
- }
- }
- }
调用代码:
- mViewPager.setPageTransformer(true, new DepthPageTransformer());
效果:
![](https://img-blog.csdn.net/20141028231742399)
2、ZoomOutPageTransformer
- package com.zhy.view;
-
- import android.annotation.SuppressLint;
- import android.support.v4.view.ViewPager;
- import android.util.Log;
- import android.view.View;
-
- public class ZoomOutPageTransformer implements ViewPager.PageTransformer
- {
- private static final float MIN_SCALE = 0.85f;
- private static final float MIN_ALPHA = 0.5f;
-
- @SuppressLint("NewApi")
- public void transformPage(View view, float position)
- {
- int pageWidth = view.getWidth();
- int pageHeight = view.getHeight();
-
- Log.e("TAG", view + " , " + position + "");
-
- if (position < -1)
- {
-
- view.setAlpha(0);
-
- } else if (position <= 1)
- {
-
- float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
- float vertMargin = pageHeight * (1 - scaleFactor) / 2;
- float horzMargin = pageWidth * (1 - scaleFactor) / 2;
- if (position < 0)
- {
- view.setTranslationX(horzMargin - vertMargin / 2);
- } else
- {
- view.setTranslationX(-horzMargin + vertMargin / 2);
- }
-
-
- view.setScaleX(scaleFactor);
- view.setScaleY(scaleFactor);
-
-
- view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE)
- / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
-
- } else
- {
-
- view.setAlpha(0);
- }
- }
- }
调用代码:
- mViewPager.setPageTransformer(true, new ZoomOutPageTransformer());
效果:
![](https://img-blog.csdn.net/20141028231715785)
效果图都是google官网上的,我们的测试图会在兼容3.0以下贴出来,不然就重复了~~
为ViewPager添加切换就一行代码是不是很happy,可惜是不兼容3.0以下的版本的,该方法的注释上写到:
setting a PageTransformer prior to Android 3.0 (API 11) will have no effect 在3.0之前的版本设置此方法是没有效果的,那么下面我们就看如何让其兼容3.0以下版本。
3、版本的向下兼容
1、不兼容的原因
首先看下为什么不兼容,3.0以下呢?
看上面的两个示例代码,代码中View的动画使用的是属性动画,而属性动画是3.0才推出的,那么这么写肯定是不兼容3.0以下了~
那么我们首先引入nineoldandroids,让动画先能在3.0以下跑再说:
修改DepthPageTransformer
- package com.zhy.view;
-
- import com.nineoldandroids.view.ViewHelper;
-
- import android.annotation.SuppressLint;
- import android.support.v4.view.ViewPager;
- import android.view.View;
-
- public class DepthPageTransformer implements ViewPager.PageTransformer
- {
- private static final float MIN_SCALE = 0.75f;
-
- public void transformPage(View view, float position)
- {
- int pageWidth = view.getWidth();
-
- if (position < -1)
- {
-
-
- ViewHelper.setAlpha(view, 0);
- } else if (position <= 0)
- {
-
-
- ViewHelper.setAlpha(view, 1);
-
- ViewHelper.setTranslationX(view, 0);
-
- ViewHelper.setScaleX(view, 1);
-
- ViewHelper.setScaleY(view, 1);
-
- } else if (position <= 1)
- {
-
-
- ViewHelper.setAlpha(view, 1 - position);
-
-
-
- ViewHelper.setTranslationX(view, pageWidth * -position);
-
-
- float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - position);
-
- ViewHelper.setScaleX(view, scaleFactor);
-
- ViewHelper.setScaleY(view, scaleFactor);
-
- } else
- {
-
-
- ViewHelper.setAlpha(view, 1);
- }
- }
- }
很简单,把所有属性动画换成ViewHelper去设置就好了。现在我们去3.0以下的机子上去运行,发现还是没有效果~~~
为什么呢?
我们再去看看setPageTransformer的源码:
- public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) {
- if (Build.VERSION.SDK_INT >= 11) {
- final boolean hasTransformer = transformer != null;
- final boolean needsPopulate = hasTransformer != (mPageTransformer != null);
- mPageTransformer = transformer;
- setChildrenDrawingOrderEnabledCompat(hasTransformer);
- if (hasTransformer) {
- mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD;
- } else {
- mDrawingOrder = DRAW_ORDER_DEFAULT;
- }
- if (needsPopulate) populate();
- }
- }
终于发现原因了,原来在此方法内部判断了如果是11以上的版本才让动画生效~~
那么,没办法了,如果想兼容,必须修改ViewPager的源码了~~
2、完美向下兼容
我们将ViewPager的源码拷贝一份至我们的项目中,修改名称为ViewPagerCompat;然后注释掉SDK版本判断那一句
public class ViewPagerCompat extends ViewGroup {
- public void setPageTransformer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer) {
-
- {
- final boolean hasTransformer = transformer != null;
- final boolean needsPopulate = hasTransformer != (mPageTransformer != null);
- mPageTransformer = transformer;
- setChildrenDrawingOrderEnabledCompat(hasTransformer);
- if (hasTransformer) {
- mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD;
- } else {
- mDrawingOrder = DRAW_ORDER_DEFAULT;
- }
- if (needsPopulate) populate();
- }
- }
...
}
注意,所有的PageTransformer使用ViewPager.PageTransformer
然后我们把项目中的ViewPager改为ViewPagerCompat;记得修改布局文件,以及MainActivity中的ViewPager为ViewPagerCompat
我们在2.3.3的模拟器上测试下效果:
![](https://img-blog.csdn.net/20141028231840899)
可以看到,我们的切换动画完美的运行在2.3.3的机器上~~so happy ~~没有ViewPager源码的童鞋不要紧,我会在文末的源码下载中加入ViewPager源码,让你可以尽情去测试~~
当然了,仅仅是兼容当然不能满足我们的好奇心,难道我们做到了兼容,还只能使用Google给的示例动画么~~我们强大的创新呢~~下面带领大家分析setPageTransformer方法,然后设计一个个性的动画切换效果
4、自定义PageTransformer实现个性切换动画
- public interface PageTransformer {
-
-
-
-
-
-
-
-
- public void transformPage(View page, float position);
- }
可以看到该接口只有一个方法,第一个是我们的view,第二个是position~~
当我们滑动时:会打印出当然ViewPager中存活的每个View以及它们的position的变化~~注意是每一个,所以建议别只log position,不然你会觉得莫名其妙的输出~~
position的可能性的值有,其实从官方示例的注释就能看出:
[-Infinity,-1) 已经看不到了
(1,+Infinity] 已经看不到了
[-1,1]
重点看[-1,1]这个区间 , 其他两个的View都已经看不到了~~
假设现在ViewPager在A页现在滑出B页,则:
A页的position变化就是( 0, -1]
B页的position变化就是[ 1 , 0 ]
知道了我们滑动时position的变化~~那么就开始设计我们的个性的切换效果;
官方给的例子,有变化透明度、偏移量、缩放的,我们准备来个不一样的,我们变化角度,即rotation;
大概的效果是这样的:
![](https://img-my.csdn.net/uploads/201410/26/1414293422_1593.gif)
下面我们分析代码:
我们设置View的旋转中心为:
ViewHelper.setPivotX(view, view.getMeasuredWidth() * 0.5f);
ViewHelper.setPivotY(view, view.getMeasuredHeight());
依然是ViewPager在A页现在滑出B页
那么A页应当在滑动过程中0度到-20度的偏移,B页应当在滑动过程中+20度到0度的偏移
结合
A页的position变化就是( 0, -1]
B页的position变化就是[ 1 , 0 ]
那么旋转的角度即:mRot = (20 * position); A页 mRot :0 ,~ -20 ; B页 mRot :20 ~ 0 ;
瞬间觉得好简单:
完整代码:
- package com.zhy.view;
-
- import com.nineoldandroids.view.ViewHelper;
-
- import android.annotation.SuppressLint;
- import android.support.v4.view.ViewPager;
- import android.util.Log;
- import android.view.View;
-
- public class RotateDownPageTransformer implements ViewPager.PageTransformer
- {
-
- private static final float ROT_MAX = 20.0f;
- private float mRot;
-
-
-
- public void transformPage(View view, float position)
- {
-
- Log.e("TAG", view + " , " + position + "");
-
- if (position < -1)
- {
-
- ViewHelper.setRotation(view, 0);
-
- } else if (position <= 1)
- {
-
- if (position < 0)
- {
-
- mRot = (ROT_MAX * position);
- ViewHelper.setPivotX(view, view.getMeasuredWidth() * 0.5f);
- ViewHelper.setPivotY(view, view.getMeasuredHeight());
- ViewHelper.setRotation(view, mRot);
- } else
- {
-
- mRot = (ROT_MAX * position);
- ViewHelper.setPivotX(view, view.getMeasuredWidth() * 0.5f);
- ViewHelper.setPivotY(view, view.getMeasuredHeight());
- ViewHelper.setRotation(view, mRot);
- }
-
-
-
-
-
- } else
- {
-
- ViewHelper.setRotation(view, 0);
- }
- }
- }
你没看错,if else 里面代码是一样的,为了好理解特意没有合并到一起~~~
到此,我们从setPageTransformer使用,到修改ViewPager做到向下兼容,直至自己定义出个性的切换效果 都已经介绍完毕~~
大家可以发挥自己的创造力,做出各种神奇的动画效果,ok,就到这里!
如果你喜欢自定义ViewPager来实现,请移步:Android 自定义 ViewPager 打造千变万化的图片切换效果
此致,本文结束,如果不是很好请谅解并留言,我会改善的----CodeParanoia