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

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表示控件大小超出后控件底部对齐。效果如下:
OK,上面是对clipChildren属性一个简单介绍,算是一个铺垫,接下来我们来看看ViewPager。
2.一个页面显示多个ViewPager的Item
我们要来解决的第一个问题是如何在一个页面上显示ViewPager的多个item,一共有两种解决方案,第一种就是我们上文所说的clipChildren属性,第二种是clipToPadding属性,我们先来看看使用第一种属性设置的ViewPager:

<?xml version="1.0" encoding="utf-8"?>
<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:clipChildren="false"
tools:context="org.lenve.myviewpagercards.MainActivity">
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginLeft="60dp"
android:layout_marginRight="60dp"
android:clipChildren="false"></android.support.v4.view.ViewPager>
</RelativeLayout>

只需要在父容器和ViewPager中都添加上clipChildren属性,然后给ViewPager设置左右两个margin,使其不致于把整个屏幕占满,就是这么简单,我们再来看看ViewPager的Adapter:

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中的代码:

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,那我们来看看显示效果:
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都有一点透明度。那我们可以使用如下方式来定义:

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即可:
viewPager.setPageTransformer(false, new AlphaTransformer());
我们再来看看运行效果:
OK,透明度的效果已经有了。很简单吧!
4.进一步了解PagerTransformer
上面是一个简答的效果,遵循这个思路,我们可以做出更多的效果,比如下面这个效果:
这是一个非常常见的效果,实现思路和前文一致,就是让ImageView动态缩放。那我们来看看这里的PagerTransformer:

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:
viewPager.setPageTransformer(false, new ScaleTransformer());
就是这么简单。其它复杂的旋转平移等都是按照这个思路来实现,这里不再赘述。
5.ViewPager结合CardView
如果你还不会使用CardView,可以参考我之前的文章Android5.0之CardView的使用,那今天我们来看看ViewPager结合CardView会产生怎样的效果呢?
那么在这之前,我想先介绍一个属性,那就是clipToPadding,这个属性是什么意思呢?它表示是否允许ViewGroup在ViewGroup的padding中进行绘制,默认情况下该属性的值为true,即不允许在ViewGroup的padding中进行绘制。那如果我设置了false呢?我们来看看:

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如下:

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中的代码:

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

显示效果如下:
OK,那这个clipToPadding属性是我们在一个页面中显示多个ViewPager item的第二种方式。这个CardView式的ViewPager我们就使用这种方式来实现。先来看看效果图:
整体思路和上文其实是一致的,我们来看看activity的布局:

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的布局:

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:

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中的代码:

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:

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的阴影做了处理 ,其他属性都没改,这样就有了我们刚才看到的效果。
本文深入探讨了ViewPager的高级用法,包括clipChildren和clipToPadding属性的巧妙运用,PageTransformer的自定义实现,以及ViewPager与CardView结合的创意展示。通过实例代码展示了如何在一个页面上显示多个ViewPager Item,创建过渡动画,调整CardView的阴影效果。
1143

被折叠的 条评论
为什么被折叠?



