一个卡片式的ViewPager,带你玩转ViewPager的PageTransformer属性!

ViewPager的基本用法不必多说,这都很简单,我们可以在ViewPager中加载一个ImageView,也可以加载一个Fragment,这都是目前非常常见的用法。那么我今天说的是ViewPager中的PageTransformer属性,用好这个属性可以让我们的应用更加出彩,OK,那我们就开始吧!

本文将从如下几方面来介绍:

 

1.clipChildren属性
2.一个页面显示多个ViewPager的Item
3.初识PagerTransformer
4.进一步了解PagerTransformer
5.ViewPager结合CardView

 

1.clipChildren属性

clipChildren属性表示是否限制子控件在该容器所在的范围内,clipChildren属性配合layout_gravity属性,可以用来设置多余部分的显示位置,我这里举一个简单的例子,比如喜马拉雅FM这个应用的首页:

一个卡片式的ViewPager,带你玩转ViewPager的PageTransformer属性!

大家注意看这个应用底部导航栏中中间一个是要比另外四个高的,这种效果很多人就会想到使用一个RelativeLayout布局来实现,其实不用那么麻烦,这种效果一个clipChildren属性就能实现,示例Demo如下:

代码:

[java] view plain copy print?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     xmlns:tools="http://schemas.android.com/tools"  
  5.     android:layout_width="match_parent"  
  6.     android:layout_height="match_parent"  
  7.     android:clipChildren="false"  
  8.     tools:context="org.lenve.clipchildren.MainActivity">  
  9.   
  10.     <LinearLayout  
  11.         android:layout_width="match_parent"  
  12.         android:layout_height="48dp"  
  13.         android:layout_alignParentBottom="true"  
  14.         android:background="#03b9fc"  
  15.         android:orientation="horizontal">  
  16.   
  17.         <ImageView  
  18.             android:layout_width="0dp"  
  19.             android:layout_height="match_parent"  
  20.             android:layout_weight="1"  
  21.             android:src="@mipmap/ic_launcher"/>  
  22.   
  23.         <ImageView  
  24.             android:layout_width="0dp"  
  25.             android:layout_height="match_parent"  
  26.             android:layout_weight="1"  
  27.             android:src="@mipmap/ic_launcher"/>  
  28.   
  29.         <ImageView  
  30.             android:layout_width="0dp"  
  31.             android:layout_height="72dp"  
  32.             android:layout_gravity="bottom"  
  33.             android:layout_weight="1"  
  34.             android:src="@mipmap/ic_launcher"/>  
  35.   
  36.         <ImageView  
  37.             android:layout_width="0dp"  
  38.             android:layout_height="match_parent"  
  39.             android:layout_weight="1"  
  40.             android:src="@mipmap/ic_launcher"/>  
  41.   
  42.         <ImageView  
  43.             android:layout_width="0dp"  
  44.             android:layout_height="match_parent"  
  45.             android:layout_weight="1"  
  46.             android:src="@mipmap/ic_launcher"/>  
  47.     </LinearLayout>  
  48. </RelativeLayout>  

大家看只需要在根节点添加clipChildren属性,然后在第三个ImageView上添加layout_gravity属性即可,layout_gravity属性值为bottom表示控件大小超出后控件底部对齐。效果如下:

一个卡片式的ViewPager,带你玩转ViewPager的PageTransformer属性!

OK,上面是对clipChildren属性一个简单介绍,算是一个铺垫,接下来我们来看看ViewPager。

2.一个页面显示多个ViewPager的Item

我们要来解决的第一个问题是如何在一个页面上显示ViewPager的多个item,一共有两种解决方案,第一种就是我们上文所说的clipChildren属性,第二种是clipToPadding属性,我们先来看看使用第一种属性设置的ViewPager:

[java] view plain copy print?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     xmlns:tools="http://schemas.android.com/tools"  
  5.     android:layout_width="match_parent"  
  6.     android:layout_height="match_parent"  
  7.     android:clipChildren="false"  
  8.     tools:context="org.lenve.myviewpagercards.MainActivity">  
  9.   
  10.     <android.support.v4.view.ViewPager  
  11.         android:id="@+id/viewpager"  
  12.         android:layout_width="match_parent"  
  13.         android:layout_height="200dp"  
  14.         android:layout_marginLeft="60dp"  
  15.         android:layout_marginRight="60dp"  
  16.         android:clipChildren="false"></android.support.v4.view.ViewPager>  
  17. </RelativeLayout>  

只需要在父容器和ViewPager中都添加上clipChildren属性,然后给ViewPager设置左右两个margin,使其不致于把整个屏幕占满,就是这么简单,我们再来看看ViewPager的Adapter:
[java] view plain copy print?
  1. public class MyVpAdater extends PagerAdapter {  
  2.     private List<Integer> list;  
  3.     private Context context;  
  4.   
  5.     public MyVpAdater(Context context, List<Integer> list) {  
  6.         this.context = context;  
  7.         this.list = list;  
  8.     }  
  9.   
  10.     @Override  
  11.     public int getCount() {  
  12.         return list.size();  
  13.     }  
  14.   
  15.     @Override  
  16.     public boolean isViewFromObject(View view, Object object) {  
  17.         return view == object;  
  18.     }  
  19.   
  20.     @Override  
  21.     public Object instantiateItem(ViewGroup container, int position) {  
  22.         ImageView iv = new ImageView(context);  
  23.         iv.setImageResource(list.get(position));  
  24.         container.addView(iv);  
  25.         return iv;  
  26.     }  
  27.   
  28.     @Override  
  29.     public void destroyItem(ViewGroup container, int position, Object object) {  
  30.         container.removeView((View) object);  
  31.     }  
  32. }  

最后再来看看Activity中的代码:
[java] view plain copy print?
  1. ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);  
  2.         viewPager.setPageMargin(80);  
  3.         viewPager.setOffscreenPageLimit(3);  
  4.         List<Integer> list = new ArrayList<>();  
  5.         list.add(R.drawable.p001);  
  6.         list.add(R.drawable.p002);  
  7.         list.add(R.drawable.p003);  
  8.         list.add(R.drawable.p004);  
  9.         list.add(R.drawable.p005);  
  10.         MyVpAdater adater = new MyVpAdater(this, list);  
  11.         viewPager.setAdapter(adater);  

比我们一般使用ViewPager多了两行代码,一个是setOffscreenPageLimit,这个是设置预加载的页数,我们知道默认情况下这个参数为1,也就是左右各预加载一页,但是我们这里要让左右各预加载两页,原因一会再说,另外一个PageMargin就好说了,就是设置ViewPager中两页之间的距离。OK,那我们来看看显示效果:

一个卡片式的ViewPager,带你玩转ViewPager的PageTransformer属性!

OK,就是这么简单,这样,我们现在已经可以在一个页面上来显示多个ViewPager中的item,接下来我们先来看看PageTransformer的简单使用。

3.初识PagerTransformer

我们知道可以给ViewPager设置一个setPagerTransformer属性,设置时候需要我们自己来实现PagerTransformer接口,实现这个接口的时候要实现该接口中的方法,transformPage,该方法接收两个参数,其中一个是position,如果你直接打印position出来可能会看得你云里雾里,实际上position表示的是第一个参数View的position,把这两个参数一起打印出来就可以找到规律了:

比如从第1页滑动到第2页:

第一页position的变化为  [0,-1]

第二页position的变化为  [1,0]

知道了这个我们就可以写一个简单的切换动画了,我希望页面上正中间的item是正常的,两边的item都有一点透明度。那我们可以使用如下方式来定义:

[java] view plain copy print?
  1. public class AlphaTransformer implements ViewPager.PageTransformer {  
  2.     private float MINALPHA = 0.5f;  
  3.   
  4.     /** 
  5.      * position取值特点: 
  6.      * 假设页面从0~1,则: 
  7.      * 第一个页面position变化为[0,-1] 
  8.      * 第二个页面position变化为[1,0] 
  9.      * 
  10.      * @param page 
  11.      * @param position 
  12.      */  
  13.     @Override  
  14.     public void transformPage(View page, float position) {  
  15.         if (position < -1 || position > 1) {  
  16.             page.setAlpha(MINALPHA);  
  17.         } else {  
  18.             //不透明->半透明  
  19.             if (position < 0) {//[0,-1]  
  20.                 page.setAlpha(MINALPHA + (1 + position) * (1 - MINALPHA));  
  21.             } else {//[1,0]  
  22.                 //半透明->不透明  
  23.                 page.setAlpha(MINALPHA + (1 - position) * (1 - MINALPHA));  
  24.             }  
  25.         }  
  26.     }  
  27. }  

定义好了之后再设置给ViewPager即可:
[java] view plain copy print?
  1. viewPager.setPageTransformer(false, new AlphaTransformer());  

我们再来看看运行效果:

一个卡片式的ViewPager,带你玩转ViewPager的PageTransformer属性!

OK,透明度的效果已经有了。很简单吧!

4.进一步了解PagerTransformer

上面是一个简答的效果,遵循这个思路,我们可以做出更多的效果,比如下面这个效果:

一个卡片式的ViewPager,带你玩转ViewPager的PageTransformer属性!

这是一个非常常见的效果,实现思路和前文一致,就是让ImageView动态缩放。那我们来看看这里的PagerTransformer:

[java] view plain copy print?
  1. public class ScaleTransformer implements ViewPager.PageTransformer {  
  2.     private static final float MIN_SCALE = 0.70f;  
  3.     private static final float MIN_ALPHA = 0.5f;  
  4.   
  5.     @Override  
  6.     public void transformPage(View page, float position) {  
  7.         if (position < -1 || position > 1) {  
  8.             page.setAlpha(MIN_ALPHA);  
  9.             page.setScaleX(MIN_SCALE);  
  10.             page.setScaleY(MIN_SCALE);  
  11.         } else if (position <= 1) { // [-1,1]  
  12.             float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));  
  13.             if (position < 0) {  
  14.                 float scaleX = 1 + 0.3f * position;  
  15.                 Log.d("google_lenve_fb", "transformPage: scaleX:" + scaleX);  
  16.                 page.setScaleX(scaleX);  
  17.                 page.setScaleY(scaleX);  
  18.             } else {  
  19.                 float scaleX = 1 - 0.3f * position;  
  20.                 page.setScaleX(scaleX);  
  21.                 page.setScaleY(scaleX);  
  22.             }  
  23.             page.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));  
  24.         }  
  25.     }  
  26. }  

然后给ViewPager设置相应的PagerTransformer:
[java] view plain copy print?
  1. viewPager.setPageTransformer(false, new ScaleTransformer());  

就是这么简单。其它复杂的旋转平移等都是按照这个思路来实现,这里不再赘述。

5.ViewPager结合CardView

如果你还不会使用CardView,可以参考我之前的文章Android5.0之CardView的使用,那今天我们来看看ViewPager结合CardView会产生怎样的效果呢?

 

那么在这之前,我想先介绍一个属性,那就是clipToPadding,这个属性是什么意思呢?它表示是否允许ViewGroup在ViewGroup的padding中进行绘制,默认情况下该属性的值为true,即不允许在ViewGroup的padding中进行绘制。那如果我设置了false呢?我们来看看:

[java] view plain copy print?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     xmlns:tools="http://schemas.android.com/tools"  
  5.     android:layout_width="match_parent"  
  6.     android:layout_height="match_parent"  
  7.     tools:context="org.lenve.myviewpagercards2.MainActivity">  
  8.   
  9.     <android.support.v4.view.ViewPager  
  10.         android:id="@+id/viewpager"  
  11.         android:layout_width="match_parent"  
  12.         android:layout_height="200dp"  
  13.         android:clipToPadding="false"  
  14.         android:paddingBottom="24dp"  
  15.         android:paddingLeft="48dp"  
  16.         android:paddingRight="48dp"  
  17.         android:paddingTop="24dp"></android.support.v4.view.ViewPager>  
  18. </RelativeLayout>  

ViewPager的Adapter如下:
[java] view plain copy print?
  1. public class MyAdapter extends PagerAdapter {  
  2.     private List<Integer> list;  
  3.     private Context context;  
  4.   
  5.     public MyAdapter(Context context, List<Integer> list) {  
  6.         this.context = context;  
  7.         this.list = list;  
  8.     }  
  9.   
  10.     @Override  
  11.     public int getCount() {  
  12.         return list.size();  
  13.     }  
  14.   
  15.     @Override  
  16.     public boolean isViewFromObject(View view, Object object) {  
  17.         return view == object;  
  18.     }  
  19.   
  20.     @Override  
  21.     public Object instantiateItem(ViewGroup container, int position) {  
  22.         ImageView iv = new ImageView(context);  
  23.         iv.setImageResource(list.get(position));  
  24.         container.addView(iv);  
  25.         return iv;  
  26.     }  
  27.   
  28.     @Override  
  29.     public void destroyItem(ViewGroup container, int position, Object object) {  
  30.         container.removeView((View) object);  
  31.     }  
  32. }  

Activity中的代码:
[java] view plain copy print?
  1. ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);  
  2. List<Integer> list = new ArrayList<>();  
  3. list.add(R.drawable.p001);  
  4. list.add(R.drawable.p002);  
  5. list.add(R.drawable.p003);  
  6. list.add(R.drawable.p004);  
  7. list.add(R.drawable.p005);  
  8. MyAdapter adapter = new MyAdapter(this, list);  
  9. viewPager.setAdapter(adapter);  
  10. viewPager.setPageMargin(20);  

显示效果如下:

一个卡片式的ViewPager,带你玩转ViewPager的PageTransformer属性!

OK,那这个clipToPadding属性是我们在一个页面中显示多个ViewPager  item的第二种方式。这个CardView式的ViewPager我们就使用这种方式来实现。先来看看效果图:

一个卡片式的ViewPager,带你玩转ViewPager的PageTransformer属性!

整体思路和上文其实是一致的,我们来看看activity的布局:

[java] view plain copy print?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     xmlns:tools="http://schemas.android.com/tools"  
  5.     android:layout_width="match_parent"  
  6.     android:layout_height="match_parent"  
  7.     tools:context="org.lenve.myviewpagercards2.MainActivity">  
  8.   
  9.     <android.support.v4.view.ViewPager  
  10.         android:id="@+id/viewpager"  
  11.         android:layout_width="match_parent"  
  12.         android:layout_height="300dp"  
  13.         android:clipToPadding="false"  
  14.         android:paddingBottom="24dp"  
  15.         android:paddingLeft="80dp"  
  16.         android:paddingRight="80dp"  
  17.         android:paddingTop="24dp"></android.support.v4.view.ViewPager>  
  18. </RelativeLayout>  

ViewPager中每一个item的布局:
[java] view plain copy print?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <android.support.v7.widget.CardView android:id="@+id/cardview"  
  3.                                     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.                                     xmlns:app="http://schemas.android.com/apk/res-auto"  
  5.                                     android:layout_width="match_parent"  
  6.                                     android:layout_height="wrap_content"  
  7.                                     android:orientation="vertical"  
  8.                                     app:cardCornerRadius="10dp">  
  9.   
  10.     <RelativeLayout  
  11.         android:layout_width="match_parent"  
  12.         android:layout_height="300dp">  
  13.   
  14.         <TextView  
  15.             android:id="@+id/tv"  
  16.             android:layout_width="match_parent"  
  17.             android:layout_height="wrap_content"  
  18.             android:layout_centerInParent="true"  
  19.             android:gravity="center"  
  20.             android:text="我是一个TextView"/>  
  21.   
  22.         <Button  
  23.             android:layout_width="96dp"  
  24.             android:layout_height="36dp"  
  25.             android:textColor="#ffffff"  
  26.             android:layout_below="@id/tv"  
  27.             android:layout_centerHorizontal="true"  
  28.             android:layout_marginTop="12dp"  
  29.             android:background="@color/colorAccent"  
  30.             android:text="我是一个按钮"/>  
  31.     </RelativeLayout>  
  32. </android.support.v7.widget.CardView>  

Adapter:
[java] view plain copy print?
  1. public class MyAdapter extends PagerAdapter {  
  2.     private List<Integer> list;  
  3.     private Context context;  
  4.     private LayoutInflater inflater;  
  5.   
  6.     public MyAdapter(Context context, List<Integer> list) {  
  7.         this.context = context;  
  8.         this.list = list;  
  9.         inflater = LayoutInflater.from(context);  
  10.     }  
  11.     @Override  
  12.     public int getCount() {  
  13.         return list.size();  
  14.     }  
  15.   
  16.     @Override  
  17.     public boolean isViewFromObject(View view, Object object) {  
  18.         return view == object;  
  19.     }  
  20.   
  21.     @Override  
  22.     public Object instantiateItem(ViewGroup container, int position) {  
  23.         View view = inflater.inflate(R.layout.vp_item, container, false);  
  24.         container.addView(view);  
  25.         return view;  
  26.     }  
  27.   
  28.     @Override  
  29.     public void destroyItem(ViewGroup container, int position, Object object) {  
  30.         container.removeView((View) object);  
  31.     }  
  32. }  

Activity中的代码:
[java] view plain copy print?
  1. ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);  
  2.         List<Integer> list = new ArrayList<>();  
  3.         list.add(R.drawable.p001);  
  4.         list.add(R.drawable.p002);  
  5.         list.add(R.drawable.p003);  
  6.         list.add(R.drawable.p004);  
  7.         list.add(R.drawable.p005);  
  8.         MyAdapter adapter = new MyAdapter(this, list);  
  9.         viewPager.setAdapter(adapter);  
  10.         viewPager.setPageMargin((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,  
  11.                 48, getResources().getDisplayMetrics()));  
  12.         viewPager.setPageTransformer(false, new ScaleTransformer(this));  

最后再来看看我们定义的PageTransformer:
[java] view plain copy print?
  1. public class ScaleTransformer implements ViewPager.PageTransformer {  
  2.     private Context context;  
  3.     private float elevation;  
  4.   
  5.     public ScaleTransformer(Context context) {  
  6.         this.context = context;  
  7.         elevation = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,  
  8.                 20, context.getResources().getDisplayMetrics());  
  9.     }  
  10.   
  11.     @Override  
  12.     public void transformPage(View page, float position) {  
  13.         if (position < -1 || position > 1) {  
  14.   
  15.         } else {  
  16.             if (position < 0) {  
  17.                 ((CardView) page).setCardElevation((1 + position) * elevation);  
  18.             } else {  
  19.                 ((CardView) page).setCardElevation((1 - position) * elevation);  
  20.             }  
  21.         }  
  22.     }  
  23. }  

很简单,我只是对CardView的阴影做了处理 ,其他属性都没改,这样就有了我们刚才看到的效果。

 


Demo下载:http://download.csdn.net/detail/u012702547/9615195

 

参考资料:

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1030/1870.html

 

以上。

 

 

 

    本文转自 一点点征服   博客园博客,原文链接http://www.cnblogs.com/ldq2016/p/7700417.html:,如需转载请自行联系原作者


上一篇:21.源码阅读(属性动画ValueAnimator-api26)


下一篇:每日总结16