zoukankan      html  css  js  c++  java
  • 一个卡片式的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这个应用的首页:

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

    代码:

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

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

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

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

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

     1 <!--?xml version="1.0" encoding="utf-8"?-->
     2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3                 android:layout_width="match_parent"
     4                 android:layout_height="match_parent"
     5                 android:clipchildren="false">
     6 
     7     <android.support.v4.view.ViewPager
     8         android:layout_width="match_parent"
     9         android:layout_height="match_parent"
    10         android:layout_marginLeft="50dp"
    11         android:layout_marginRight="50dp"/>
    12 
    13 </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 }</integer></integer>

    最后再来看看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);</integer>

    比我们一般使用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即可:

    1 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:

    1 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 android:layout_height="match_parent" android:layout_width="match_parent" tools:context="org.lenve.myviewpagercards2.MainActivity" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
    3  
    4     </android.support.v4.view.viewpager>
    5 </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 }</integer></integer>

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

    显示效果如下:

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

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

    1 <!--?xml version="1.0" encoding="utf-8"?-->
    2 <relativelayout android:layout_height="match_parent" android:layout_width="match_parent" tools:context="org.lenve.myviewpagercards2.MainActivity" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
    3  
    4     </android.support.v4.view.viewpager>
    5 </relativelayout>

    ViewPager中每一个item的布局:

    1 <!--?xml version="1.0" encoding="utf-8"?-->
    2  
    3  
    4     <relativelayout android:layout_height="300dp" android:layout_width="match_parent">
    5  
    6         <textview android:gravity="center" android:id="@+id/tv" android:layout_centerinparent="true" android:layout_height="wrap_content" android:layout_width="match_parent" android:text="我是一个TextView"><button android:background="@color/colorAccent" android:layout_below="@id/tv" android:layout_centerhorizontal="true" android:layout_height="36dp" android:layout_margintop="12dp" android:layout_width="96dp" android:text="我是一个按钮" android:textcolor="#ffffff"></button></textview></relativelayout></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));</integer>

    最后再来看看我们定义的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的阴影做了处理 ,其他属性都没改,这样就有了我们刚才看到的效果。

  • 相关阅读:
    if()中的判断条件为什么被判断不通过
    2016-10-1219:50:40
    学习C语言主流编译器的使用方法
    请帮忙看下为什么返回值不正确
    puts()和putchar()的差异
    这题的最短路线怎么求~
    各路大神大显神通!帮帮忙如何使用顺序表实现以下任务
    网络协议学习笔记(九)CDN和数据中心
    网络协议学习笔记(八)DNS协议和HttpDNS协议
    网络协议学习笔记(七)流媒体协议和P2P协议
  • 原文地址:https://www.cnblogs.com/huolongluo/p/6432836.html
Copyright © 2011-2022 走看看