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

xiaoxiao2025-04-30  19

版权声明:本文为sang原创文章,转载请注明出处。 https://blog.csdn.net/u012702547/article/details/52334161

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

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

1.clipChildren属性2.一个页面显示多个ViewPager的Item3.初识PagerTransformer4.进一步了解PagerTransformer5.ViewPager结合CardView

1.clipChildren属性

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

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

代码:

<?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.clipchildren.MainActivity"> <LinearLayout android:layout_width= "match_parent" android:layout_height= "48dp" android:layout_alignParentBottom= "true" android:background= "#03b9fc" android:orientation= "horizontal"> <ImageView android:layout_width= "0dp" android:layout_height= "match_parent" android:layout_weight= "1" android:src= "@mipmap/ic_launcher"/> <ImageView android:layout_width= "0dp" android:layout_height= "match_parent" android:layout_weight= "1" android:src= "@mipmap/ic_launcher"/> <ImageView android:layout_width= "0dp" android:layout_height= "72dp" android:layout_gravity= "bottom" android:layout_weight= "1" android:src= "@mipmap/ic_launcher"/> <ImageView android:layout_width= "0dp" android:layout_height= "match_parent" android:layout_weight= "1" android:src= "@mipmap/ic_launcher"/> <ImageView android:layout_width= "0dp" android:layout_height= "match_parent" android:layout_weight= "1" android:src= "@mipmap/ic_launcher"/> </LinearLayout> </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:

public class MyVpAdater extends PagerAdapter { private List<Integer> list; private Context context; public MyVpAdater(Context context, List<Integer> list) { this.context = context; this.list = list; } @Override public int getCount() { return list.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, int position) { ImageView iv = new ImageView(context); iv.setImageResource(list.get(position)); container.addView(iv); return iv; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } } 最后再来看看Activity中的代码:

ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager); viewPager.setPageMargin( 80); viewPager.setOffscreenPageLimit( 3); List<Integer> list = new ArrayList<>(); list.add(R.drawable.p001); list.add(R.drawable.p002); list.add(R.drawable.p003); list.add(R.drawable.p004); list.add(R.drawable.p005); MyVpAdater adater = new MyVpAdater( this, list); 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都有一点透明度。那我们可以使用如下方式来定义:

public class AlphaTransformer implements ViewPager.PageTransformer { private float MINALPHA = 0.5f; /** * position取值特点: * 假设页面从0~1,则: * 第一个页面position变化为[0,-1] * 第二个页面position变化为[1,0] * * @param page * @param position */ @Override public void transformPage(View page, float position) { if (position < - 1 || position > 1) { page.setAlpha(MINALPHA); } else { //不透明->半透明 if (position < 0) { //[0,-1] page.setAlpha(MINALPHA + ( 1 + position) * ( 1 - MINALPHA)); } else { //[1,0] //半透明->不透明 page.setAlpha(MINALPHA + ( 1 - position) * ( 1 - MINALPHA)); } } } } 定义好了之后再设置给ViewPager即可:

viewPager.setPageTransformer(false, new AlphaTransformer()); 我们再来看看运行效果:

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

4.进一步了解PagerTransformer

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

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

public class ScaleTransformer implements ViewPager.PageTransformer { private static final float MIN_SCALE = 0.70f; private static final float MIN_ALPHA = 0.5f; @Override public void transformPage(View page, float position) { if (position < - 1 || position > 1) { page.setAlpha(MIN_ALPHA); page.setScaleX(MIN_SCALE); page.setScaleY(MIN_SCALE); } else if (position <= 1) { // [-1,1] float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position)); if (position < 0) { float scaleX = 1 + 0.3f * position; Log.d( "google_lenve_fb", "transformPage: scaleX:" + scaleX); page.setScaleX(scaleX); page.setScaleY(scaleX); } else { float scaleX = 1 - 0.3f * position; page.setScaleX(scaleX); page.setScaleY(scaleX); } page.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / ( 1 - MIN_SCALE) * ( 1 - MIN_ALPHA)); } } } 然后给ViewPager设置相应的PagerTransformer:

viewPager.setPageTransformer(false, new ScaleTransformer()); 就是这么简单。其它复杂的旋转平移等都是按照这个思路来实现,这里不再赘述。

5.ViewPager结合CardView

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

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

<?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" tools:context= "org.lenve.myviewpagercards2.MainActivity"> <android.support.v4.view.ViewPager android:id= "@+id/viewpager" android:layout_width= "match_parent" android:layout_height= "200dp" android:clipToPadding= "false" android:paddingBottom= "24dp" android:paddingLeft= "48dp" android:paddingRight= "48dp" android:paddingTop= "24dp"></android.support.v4.view.ViewPager> </RelativeLayout> ViewPager的Adapter如下:

public class MyAdapter extends PagerAdapter { private List<Integer> list; private Context context; public MyAdapter(Context context, List<Integer> list) { this.context = context; this.list = list; } @Override public int getCount() { return list.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, int position) { ImageView iv = new ImageView(context); iv.setImageResource(list.get(position)); container.addView(iv); return iv; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } } Activity中的代码:

ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager); List<Integer> list = new ArrayList<>(); list.add(R.drawable.p001); list.add(R.drawable.p002); list.add(R.drawable.p003); list.add(R.drawable.p004); list.add(R.drawable.p005); MyAdapter adapter = new MyAdapter( this, list); viewPager.setAdapter(adapter); viewPager.setPageMargin( 20); 显示效果如下:

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

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

<?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" tools:context= "org.lenve.myviewpagercards2.MainActivity"> <android.support.v4.view.ViewPager android:id= "@+id/viewpager" android:layout_width= "match_parent" android:layout_height= "300dp" android:clipToPadding= "false" android:paddingBottom= "24dp" android:paddingLeft= "80dp" android:paddingRight= "80dp" android:paddingTop= "24dp"></android.support.v4.view.ViewPager> </RelativeLayout> ViewPager中每一个item的布局:

<?xml version= "1.0" encoding= "utf-8"?> <android.support.v7.widget.CardView android:id= "@+id/cardview" xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:app= "http://schemas.android.com/apk/res-auto" android:layout_width= "match_parent" android:layout_height= "wrap_content" android:orientation= "vertical" app:cardCornerRadius= "10dp"> <RelativeLayout android:layout_width= "match_parent" android:layout_height= "300dp"> <TextView android:id= "@+id/tv" android:layout_width= "match_parent" android:layout_height= "wrap_content" android:layout_centerInParent= "true" android:gravity= "center" android:text= "我是一个TextView"/> <Button android:layout_width= "96dp" android:layout_height= "36dp" android:textColor= "#ffffff" android:layout_below= "@id/tv" android:layout_centerHorizontal= "true" android:layout_marginTop= "12dp" android:background= "@color/colorAccent" android:text= "我是一个按钮"/> </RelativeLayout> </android.support.v7.widget.CardView> Adapter:

public class MyAdapter extends PagerAdapter { private List<Integer> list; private Context context; private LayoutInflater inflater; public MyAdapter(Context context, List<Integer> list) { this.context = context; this.list = list; inflater = LayoutInflater.from(context); } @Override public int getCount() { return list.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, int position) { View view = inflater.inflate(R.layout.vp_item, container, false); container.addView(view); return view; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } } Activity中的代码:

ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager); List<Integer> list = new ArrayList<>(); list.add(R.drawable.p001); list.add(R.drawable.p002); list.add(R.drawable.p003); list.add(R.drawable.p004); list.add(R.drawable.p005); MyAdapter adapter = new MyAdapter( this, list); viewPager.setAdapter(adapter); viewPager.setPageMargin(( int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, getResources().getDisplayMetrics())); viewPager.setPageTransformer( false, new ScaleTransformer( this)); 最后再来看看我们定义的PageTransformer:

public class ScaleTransformer implements ViewPager.PageTransformer { private Context context; private float elevation; public ScaleTransformer(Context context) { this.context = context; elevation = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, context.getResources().getDisplayMetrics()); } @Override public void transformPage(View page, float position) { if (position < - 1 || position > 1) { } else { if (position < 0) { ((CardView) page).setCardElevation(( 1 + position) * elevation); } else { ((CardView) page).setCardElevation(( 1 - position) * elevation); } } } } 很简单,我只是对CardView的阴影做了处理 ,其他属性都没改,这样就有了我们刚才看到的效果。

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

参考资料:

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

以上。

转自:https://blog.csdn.net/u012702547/article/details/52334161
转载请注明原文地址: https://www.6miu.com/read-5029509.html

最新回复(0)