1.引言
ViewPager是我們比較熟悉的一個控件,用於視圖切換或作爲首頁的切換,默認是沒有動畫切換效果的,當然我們可以通過setPageTransform來添加各種各樣的動畫,這裏我們介紹另外一種方法,自定義自帶動畫切換效果的ViewPager。
2.準備工作
首先分析我們要實現動畫切換效果,我們必須要準備的工作:
1.首先必須獲取兩個切換的視圖,mLeftView 和 mRightView。
2.然後還必須有一個變化的梯度值,用於控制切換過程中的值變化。
新建一個類 ViewPagerWithTransformAnim.java 繼承自ViewPager
public class ViewPageWithTransformAnim extends ViewPager{
//兩個View
private View mLeft;
private View mRight;
//變化的梯度
private float mTrans;
//縮放的值
private float mScale;
//縮放的最小值,從0.5 到 1
private static final float MIN_SCALE = 0.5f;
public ViewPageWithTransformAnim(Context context) {
super(context);
}
public ViewPageWithTransformAnim(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onPageScrolled(int position, float offset, int pix) {
Log.i("meng.li", "position = "+position +" offset = "+offset+" pix = "+pix);
super.onPageScrolled(position, offset, pix);
}
}
ViewPager中有一個onPageScrolled方法,我們可以在這裏獲取我們需要的東西。
我們觀察onPageScrolled方法的log信息:
從第0頁滑動到第1頁
從第1頁回到第0頁
總結下規律
0頁到1頁 position 0 ; offset 0-1
1頁到0頁 position 0 ; offset 1-0
下面仔細研究下這幾個參數:
直接說測試結果:
在非第一頁與最後一頁時,滑動到下一頁,position爲當前頁位置;滑動到上一頁:position爲當前頁-1
positionOffset 滑動到下一頁,[0,1)區間上變化;滑動到上一頁:(1,0]區間上變化
positionOffsetPixels這個和positionOffset很像:滑動到下一頁,[0,寬度)區間上變化;滑動到上一頁:(寬度,0]區間上變化
第一頁時:滑動到上一頁position=0 ,其他基本爲0 ;最後一頁滑動到下一頁 position爲當前頁位置,其他兩個參數爲0
豁然發現,我們需要的步驟的第二步解決了,positionOffset很適合作爲,漸變,縮放的控制參數;positionOffsetPixels則可以作爲平移等的控制參數。
那麼如何獲得當前View和目的View呢:
分享幾個我的歧途:
1、【錯誤】我通過getChildAt(position),getChildAt(position+1),getChildAt(position-1)獲得滑動時,左右的兩個View;乍一看,還真覺得不錯~~~在代碼寫出來,再乍效果也出不來~~錯誤原因:我們忽略一個特別大的東西,ViewPager的機制,滑動時動態加載和刪除View,ViewPager其實只會維持2到3個View,而position的範圍基本屬於無限~~
2、【錯誤】我通過getCurrentItem獲得當前的位置,然後+1,-1獲得後一個或者前一個~~正在竊喜,趕快代碼改過來,效果怎麼也不對,亂七八糟的~~仔細觀察日誌,這個getCurrentItem當用戶手指離開的屏幕,Page還在動畫執行時,就改變了~~難怪~整個滑動過程並不是固定的~~唉,心都碎了~
3、【錯誤】position在整個滑動的過程中是不變化的,而且ViewPager會保存2個或3個View;那麼我考慮,如果是第一頁、或者最後一頁那麼我取getChildAt(0)和getChildAt(1),如果在其他頁面則爲getChildAt(0),getChildAt(2),然後經過一系列的變化~我想這會總該對了吧,於是我遇到第一問題,第一頁的時候,不管左右position都爲0,尼瑪,這哪個爲左View,哪個爲右View~~
說了這麼多錯誤,大家可以繞過這些彎路,也能從這些彎路里面看出點什麼
說了這麼多錯誤,大家可以繞過這些彎路,也能從這些彎路里面看出點什麼~
下面說正確的,其實ViewPager在添加一個View或者銷燬一個View時,是我們自己的PageAdapter中控制的,於是我們可以在ViewPager裏面維繫一個HashMap<Position,View>,然後滑動的時候,通過get(position)取出,比如上述效果,始終是右邊的View變化,要麼從小到大,要麼從大到小
那麼滑到下一頁:左邊的View:map.get(position) ,右邊的View : map.get(position+1) .
那麼滑到上一頁:左邊的View : map.get(position) , 右邊的View : map.get(position+1) , 一樣的,因爲滑到上一頁,position爲當前頁-1
好了,至此,我們分析了且解決了所有步驟
代碼: MainActivity.java
public class MainActivity extends Activity {
// private ViewPager viewPager;
//這裏是爲了兼容3.0版本下設置動畫效果從新改寫的ViewPager
// private ViewPagerCompat viewPager;
//自定義帶動畫切換效果的ViewPager
private ViewPageWithTransformAnim viewPager;
private int[] mImgId = new int[]{R.drawable.guide_image1,R.drawable.guide_image2,R.drawable.guide_image3};
List<ImageView> mImages = new ArrayList<ImageView>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPageWithTransformAnim)findViewById(R.id.view_pager);
viewPager.setAdapter(new PagerAdapter() {
//實例化 Item 創建ImageView
@Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView imageView = new ImageView(MainActivity.this);
imageView.setImageResource(mImgId[position]);
imageView.setScaleType(ScaleType.CENTER_CROP);
container.addView(imageView);
mImages.add(imageView);
//添加到View中
viewPager.setViewForPosition(imageView,position);
return imageView;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
//判斷view是否來自於 arg1 arg1 是初始化的時候添加進去的
return arg0 == arg1;
}
@Override
public int getCount() {
//獲取視圖的長度
return mImgId.length;
}
@Override
public void destroyItem(ViewGroup container, int position,
Object object) {
//移除視圖
viewPager.removeViewFromPosition(position);
//移除視圖
container.removeView(mImages.get(position));
}
});
}
}
這個很常見的代碼,就是初始化ViewPager~~就沒啥可說的了~~有一點需要注意:在instantiateItem方法,我們多調用了一個mViewPager.setObjectForPosition(imageView, position);其實就是爲了給我們的Map存值
自定義ViewPager
/*
* 自定義的帶動畫切換效果的ViewPager
*/
/*需要有哪些準備
* a.需要拿到當前切換的兩個 View
* b.需要拿到一個動畫的梯度值
* Translation 和 Scale
*/
public class ViewPageWithTransformAnim extends ViewPager{
private Map<Integer, View> vChildren= new HashMap<Integer, View>();
public void setViewForPosition(View view,int position){
vChildren.put(position, view);
}
public void removeViewFromPosition(int position){
vChildren.remove(position);
}
//兩個View
private View mLeft;
private View mRight;
//變化的梯度
private float mTrans;
//縮放的值
private float mScale;
//縮放的最小值,從0.5 到 1
private static final float MIN_SCALE = 0.5f;
public ViewPageWithTransformAnim(Context context) {
super(context);
}
public ViewPageWithTransformAnim(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onPageScrolled(int position, float offset, int pix) {
// Log.i("meng.li", "position = "+position +" offset = "+offset+" pix = "+pix);
mLeft = vChildren.get(position);
mRight = vChildren.get(position+1);
//添加動畫效果
animStack(mLeft,mRight,offset,pix);
Log.i("meng.li", getCurrentItem() +" -- "+getChildCount());
super.onPageScrolled(position, offset, pix);
}
private void animStack(View left,View right,float offset,int offsetPixels){
if(right != null){
//從0頁到1頁, offset: 0-1
//從0 逐漸變到1
mScale = (1 - MIN_SCALE)* offset + MIN_SCALE;
//從 0 到寬度的變化
mTrans = -getWidth() -getPageMargin() + offsetPixels;
ViewHelper.setScaleX(right, mScale);
ViewHelper.setScaleY(right, mScale);
ViewHelper.setTranslationX(right, mTrans);
}
if(left != null){
//讓其保持在頂部繪製
left.bringToFront();
}
}
}
可以看到,核心代碼都是onPageScrolled,我們通過findViewFromObject(position); findViewFromObject(position + 1);分別獲取了左右兩邊的View,然後添加動畫效果;當前這個例子添加了兩個動畫,一個是從0.5放大到1.0或者1.0縮小到0.5,沒錯由我們的positionOffset提供梯度的變化~~還有個平移的動畫:下一頁直接移動到當前屏幕(默認是在右邊,可以註釋這個效果,怎麼運行看看),然後不斷的通過positionOffsetPixels抵消原來默認移動時的位移,讓用戶感覺它就在原地放大縮小~~
<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="com.example.viewpageranimation.MainActivity" >
<com.example.viewpageranimation.ViewPageWithTransformAnim
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
實現的效果爲:
4、JazzyViewPager的使用
其實上面的實現就是github上JazzyViewPager的源碼,用法不用說了,就是我們的MainActivity,它內置了大概10來種效果,我們可以通過代碼或者佈局上面設置動畫效果~~我們上面的例子效果,它叫做Stack;
使用JazzViewPager的代碼:其實基本一樣~~最後也會貼上JazzyViewPager的源碼的下載
MainActivity
package com.jfeinstein.jazzyviewpager;
import com.jfeinstein.jazzyviewpager.JazzyViewPager.TransitionEffect;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
public class MainActivity extends Activity
{
protected static final String TAG = "MainActivity";
private int[] mImgIds;
private JazzyViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImgIds = new int[] { R.drawable.a, R.drawable.b, R.drawable.c,
R.drawable.d };
mViewPager = (JazzyViewPager) findViewById(R.id.id_viewPager);
//設置切換效果
mViewPager.setTransitionEffect(TransitionEffect.Stack);
mViewPager.setAdapter(new PagerAdapter()
{
@Override
public boolean isViewFromObject(View arg0, Object arg1)
{
return arg0 == arg1;
}
@Override
public void destroyItem(ViewGroup container, int position,
Object object)
{
container.removeView((View) object);
}
@Override
public Object instantiateItem(ViewGroup container, int position)
{
ImageView imageView = new ImageView(MainActivity.this);
imageView.setImageResource(mImgIds[position]);
imageView.setScaleType(ScaleType.CENTER_CROP);
container.addView(imageView);
mViewPager.setObjectForPosition(imageView, position);
return imageView;
}
@Override
public int getCount()
{
return mImgIds.length;
}
});
}
}
與我們的代碼唯一區別就是://設置切換效果
mViewPager.setTransitionEffect(TransitionEffect.Stack);
它有12中可選的切換效果,其實就是寫了12個切換的動畫~~~
好了,最後附上一個我比較喜歡的效果:Tablet
JazzyViewPager 下載地址:https://github.com/jfeinstein10/JazzyViewPager
本文轉載自:http://blog.csdn.net/lmj623565791/article/details/38026503