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的陰影做了處理 ,其他屬性都沒改,這樣就有了我們剛才看到的效果。
Demo下載:http://download.csdn.net/detail/u012702547/9615195
參考資料:
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1030/1870.html
轉自:http://blog.csdn.net/u012702547/article/details/52334161
