您的位置:首页 > 其它

ViewPager详解-----CodeParanoia

2016-02-15 14:22 357 查看
(在本文中引用到了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之间结合的使用。他们是
FragmentPagerAdapterFragmentStatePagerAdapter
这两个类都有简单的代码示例去展示如何构建一个用户界面


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结合使用时使用。他们是
FragmentPagerAdapterFragmentStatePagerAdapter


以下是转载自大神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、布局文件

[html] view
plain copy







<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

[java] view
plain copy







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

[java] view
plain copy







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) { // [-Infinity,-1)

// This page is way off-screen to the left.

view.setAlpha(0);

} else if (position <= 0) { // [-1,0]

// Use the default slide transition when moving to the left page

view.setAlpha(1);

view.setTranslationX(0);

view.setScaleX(1);

view.setScaleY(1);

} else if (position <= 1) { // (0,1]

// Fade the page out.

view.setAlpha(1 - position);

// Counteract the default slide transition

view.setTranslationX(pageWidth * -position);

// Scale the page down (between MIN_SCALE and 1)

float scaleFactor = MIN_SCALE

+ (1 - MIN_SCALE) * (1 - Math.abs(position));

view.setScaleX(scaleFactor);

view.setScaleY(scaleFactor);

} else { // (1,+Infinity]

// This page is way off-screen to the right.

view.setAlpha(0);

}

}

}

调用代码:

[java] view
plain copy







mViewPager.setPageTransformer(true, new DepthPageTransformer());

效果:



2、ZoomOutPageTransformer

[java] view
plain copy







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)

{ // [-Infinity,-1)

// This page is way off-screen to the left.

view.setAlpha(0);

} else if (position <= 1) //a页滑动至b页 ; a页从 0.0 -1 ;b页从1 ~ 0.0

{ // [-1,1]

// Modify the default slide transition to shrink the page as well

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);

}

// Scale the page down (between MIN_SCALE and 1)

view.setScaleX(scaleFactor);

view.setScaleY(scaleFactor);

// Fade the page relative to its size.

view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE)

/ (1 - MIN_SCALE) * (1 - MIN_ALPHA));

} else

{ // (1,+Infinity]

// This page is way off-screen to the right.

view.setAlpha(0);

}

}

}

调用代码:

[java] view
plain copy







mViewPager.setPageTransformer(true, new ZoomOutPageTransformer());

效果:



效果图都是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

[java] view
plain copy







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)

{ // [-Infinity,-1)

// This page is way off-screen to the left.

// view.setAlpha(0);

ViewHelper.setAlpha(view, 0);

} else if (position <= 0)// a页滑动至b页 ; a页从 0.0 -1 ;b页从1 ~ 0.0

{ // [-1,0]

// Use the default slide transition when moving to the left page

// view.setAlpha(1);

ViewHelper.setAlpha(view, 1);

// view.setTranslationX(0);

ViewHelper.setTranslationX(view, 0);

// view.setScaleX(1);

ViewHelper.setScaleX(view, 1);

// view.setScaleY(1);

ViewHelper.setScaleY(view, 1);

} else if (position <= 1)

{ // (0,1]

// Fade the page out.

// view.setAlpha(1 - position);

ViewHelper.setAlpha(view, 1 - position);

// Counteract the default slide transition

// view.setTranslationX(pageWidth * -position);

ViewHelper.setTranslationX(view, pageWidth * -position);

// Scale the page down (between MIN_SCALE and 1)

float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - position);

// view.setScaleX(scaleFactor);

ViewHelper.setScaleX(view, scaleFactor);

// view.setScaleY(1);

ViewHelper.setScaleY(view, scaleFactor);

} else

{ // (1,+Infinity]

// This page is way off-screen to the right.

// view.setAlpha(0);

ViewHelper.setAlpha(view, 1);

}

}

}

很简单,把所有属性动画换成ViewHelper去设置就好了。现在我们去3.0以下的机子上去运行,发现还是没有效果~~~

为什么呢?

我们再去看看setPageTransformer的源码:

[java] view
plain copy







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 {

[java] view
plain copy







public void setPageTransformer(boolean reverseDrawingOrder, ViewPager.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();

}

}

...

}

注意,所有的PageTransformer使用ViewPager.PageTransformer

然后我们把项目中的ViewPager改为ViewPagerCompat;记得修改布局文件,以及MainActivity中的ViewPager为ViewPagerCompat

我们在2.3.3的模拟器上测试下效果:



可以看到,我们的切换动画完美的运行在2.3.3的机器上~~so happy ~~没有ViewPager源码的童鞋不要紧,我会在文末的源码下载中加入ViewPager源码,让你可以尽情去测试~~

当然了,仅仅是兼容当然不能满足我们的好奇心,难道我们做到了兼容,还只能使用Google给的示例动画么~~我们强大的创新呢~~下面带领大家分析setPageTransformer方法,然后设计一个个性的动画切换效果


4、自定义PageTransformer实现个性切换动画

[java] view
plain copy







public interface PageTransformer {

/**

* Apply a property transformation to the given page.

*

* @param page Apply the transformation to this page

* @param position Position of page relative to the current front-and-center

* position of the pager. 0 is front and center. 1 is one full

* page position to the right, and -1 is one page position to the left.

*/

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;

大概的效果是这样的:



下面我们分析代码:

我们设置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 ;

瞬间觉得好简单:

完整代码:

[java] view
plain copy







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)

{ // [-Infinity,-1)

// This page is way off-screen to the left.

ViewHelper.setRotation(view, 0);

} else if (position <= 1) // a页滑动至b页 ; a页从 0.0 ~ -1 ;b页从1 ~ 0.0

{ // [-1,1]

// Modify the default slide transition to shrink the page as well

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);

}

// Scale the page down (between MIN_SCALE and 1)

// Fade the page relative to its size.

} else

{ // (1,+Infinity]

// This page is way off-screen to the right.

ViewHelper.setRotation(view, 0);

}

}

}

你没看错,if else 里面代码是一样的,为了好理解特意没有合并到一起~~~

到此,我们从setPageTransformer使用,到修改ViewPager做到向下兼容,直至自己定义出个性的切换效果 都已经介绍完毕~~

大家可以发挥自己的创造力,做出各种神奇的动画效果,ok,就到这里!

如果你喜欢自定义ViewPager来实现,请移步:Android 自定义 ViewPager 打造千变万化的图片切换效果

此致,本文结束,如果不是很好请谅解并留言,我会改善的----CodeParanoia
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: