前言:在做App的Splash頁面時有一個漂亮的ViewPager切換動畫,不僅能讓人耳目一新,而且在開發中面對PM的需求也能做到遊刃有餘。
先看效果圖
目錄
- 自定義ViewPagerTransform方法介紹
- 自定義ViewPagerTransform
1:自定義ViewPagerTransform方法介紹
直接上碼
private void initViewPager1(){
vierPage1.setAdapter(new PagerAdapter() {
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(tvLists.get(position));
return tvLists.get(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(tvLists.get(position));
}
@Override
public int getCount() {
return tvLists.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
});
vierPage1.setPageTransformer(true,new DepthPageTransformer());
}
private void setData() {
int[] colors = new int[]{ContextCompat.getColor(this,R.color.green),
ContextCompat.getColor(this,R.color.red),
ContextCompat.getColor(this,R.color.mediumvioletred)};
TextView textView = null;
for (int i = 0; i < colors.length; i++) {
textView = new TextView(this);
textView.setBackgroundColor(colors[i]);
textView.setText(i+"");
textView.setGravity(Gravity.CENTER);
tvLists.add(textView);
}
}
這裏我給給ViewPager設置3個TextView,分別是0,1,2(爲什麼是TextView呢,這裏後面有用到),分別給了不同的背景色,關鍵在於
vierPage1.setPageTransformer(true,new DepthPageTransformer());
DepthPageTransformer
public class DepthPageTransformer implements ViewPager.PageTransformer {
private static final String TAG = "DepthPageTransformer";
private static final float MIN_SCALE = 0.75f;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
/**
* position取值特點:
* 假設頁面從0~1,則:
* 第一個頁面position變化爲[0,-1] 當前的View
* 第二個頁面position變化爲[1,0] 進入的View
*
* @param page
* @param position
*/
@Override
public void transformPage(View view, float position) {
Log.d(TAG,((TextView)view).getText() + "___" + position);
int pageWidth = view.getWidth();
if (position < -1) { // [-Infinity,-1) 不可見的View
view.setAlpha(0);
} else if (position <= 0) { // [-1,0] 當前的View
view.setAlpha(1);
view.setTranslationX(0);
view.setScaleX(1);
view.setScaleY(1);
} else if (position <= 1) { // (0,1] 進入的View
view.setAlpha(1 - position);
view.setTranslationX(pageWidth * -position);
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else { (1,+Infinity] //不可見的View
view.setAlpha(0);
}
}
}
要使用自定義切換效果必須實現ViewPager.PageTransformer
它的transformerPage 方法雖然有註釋,但是不是很好理解,這時候TextView用處就上場了,來看看Log打印出來的東西
頁面進入的時候:
05-24 01:46:21.456 1645-1645/norton.animademo D/DepthPageTransformer: 0___0.0
05-24 01:46:21.456 1645-1645/norton.animademo D/DepthPageTransformer: 1___1.0
由 0 ->1
05-24 01:46:25.327 1645-1645/norton.animademo D/DepthPageTransformer: 0___-0.052083332
05-24 01:46:25.327 1645-1645/norton.animademo D/DepthPageTransformer: 1___0.9479167
05-24 01:46:25.345 1645-1645/norton.animademo D/DepthPageTransformer: 0___-0.24722221
05-24 01:46:25.345 1645-1645/norton.animademo D/DepthPageTransformer: 1___0.75277776
05-24 01:46:25.366 1645-1645/norton.animademo D/DepthPageTransformer: 0___-0.52847224
05-24 01:46:25.366 1645-1645/norton.animademo D/DepthPageTransformer: 1___0.47152779
05-24 01:46:25.380 1645-1645/norton.animademo D/DepthPageTransformer: 0___-0.77708334
05-24 01:46:25.380 1645-1645/norton.animademo D/DepthPageTransformer: 1___0.22291666
05-24 01:46:25.394 1645-1645/norton.animademo D/DepthPageTransformer: 0___-0.90833336
05-24 01:46:25.394 1645-1645/norton.animademo D/DepthPageTransformer: 1___0.09166667
05-24 01:46:25.411 1645-1645/norton.animademo D/DepthPageTransformer: 0___-0.9763889
05-24 01:46:25.411 1645-1645/norton.animademo D/DepthPageTransformer: 1___0.023611112
05-24 01:46:25.428 1645-1645/norton.animademo D/DepthPageTransformer: 0___-0.99722224
05-24 01:46:25.428 1645-1645/norton.animademo D/DepthPageTransformer: 1___0.0027777778
05-24 01:46:25.444 1645-1645/norton.animademo D/DepthPageTransformer: 0___-1.0
05-24 01:46:25.444 1645-1645/norton.animademo D/DepthPageTransformer: 1___0.0
由1->2
05-24 01:49:49.110 1645-1645/norton.animademo D/DepthPageTransformer: 1___-0.09791667
05-24 01:49:49.110 1645-1645/norton.animademo D/DepthPageTransformer: 2___0.90208334
05-24 01:49:49.110 1645-1645/norton.animademo D/DepthPageTransformer: 0___-1.0979167
05-24 01:49:49.127 1645-1645/norton.animademo D/DepthPageTransformer: 1___-0.37013888
05-24 01:49:49.127 1645-1645/norton.animademo D/DepthPageTransformer: 2___0.6298611
05-24 01:49:49.127 1645-1645/norton.animademo D/DepthPageTransformer: 0___-1.3701389
05-24 01:49:49.143 1645-1645/norton.animademo D/DepthPageTransformer: 1___-0.58958334
05-24 01:49:49.143 1645-1645/norton.animademo D/DepthPageTransformer: 2___0.41041666
05-24 01:49:49.143 1645-1645/norton.animademo D/DepthPageTransformer: 0___-1.5895833
05-24 01:49:49.160 1645-1645/norton.animademo D/DepthPageTransformer: 1___-0.84930557
05-24 01:49:49.160 1645-1645/norton.animademo D/DepthPageTransformer: 2___0.15069444
05-24 01:49:49.160 1645-1645/norton.animademo D/DepthPageTransformer: 0___-1.8493055
05-24 01:49:49.180 1645-1645/norton.animademo D/DepthPageTransformer: 1___-0.9611111
05-24 01:49:49.180 1645-1645/norton.animademo D/DepthPageTransformer: 2___0.03888889
05-24 01:49:49.180 1645-1645/norton.animademo D/DepthPageTransformer: 0___-1.9611111
05-24 01:49:49.196 1645-1645/norton.animademo D/DepthPageTransformer: 1___-0.99375
05-24 01:49:49.196 1645-1645/norton.animademo D/DepthPageTransformer: 2___0.00625
05-24 01:49:49.196 1645-1645/norton.animademo D/DepthPageTransformer: 0___-1.99375
05-24 01:49:49.212 1645-1645/norton.animademo D/DepthPageTransformer: 1___-0.99930555
05-24 01:49:49.212 1645-1645/norton.animademo D/DepthPageTransformer: 2___6.9444446E-4
05-24 01:49:49.212 1645-1645/norton.animademo D/DepthPageTransformer: 0___-1.9993056
05-24 01:49:49.226 1645-1645/norton.animademo D/DepthPageTransformer: 1___-1.0
05-24 01:49:49.226 1645-1645/norton.animademo D/DepthPageTransformer: 2___0.0
05-24 01:49:49.229 1645-1645/norton.animademo D/DepthPageTransformer: 0___-2.0
由2->1
05-24 01:50:20.677 1645-1645/norton.animademo D/DepthPageTransformer: 1___-0.9444444
05-24 01:50:20.677 1645-1645/norton.animademo D/DepthPageTransformer: 2___0.055555556
05-24 01:50:20.694 1645-1645/norton.animademo D/DepthPageTransformer: 1___-0.68680555
05-24 01:50:20.694 1645-1645/norton.animademo D/DepthPageTransformer: 2___0.31319445
05-24 01:50:20.710 1645-1645/norton.animademo D/DepthPageTransformer: 1___-0.4173611
05-24 01:50:20.710 1645-1645/norton.animademo D/DepthPageTransformer: 2___0.58263886
05-24 01:50:20.720 1645-1645/norton.animademo D/DepthPageTransformer: 1___-0.33402777
05-24 01:50:20.720 1645-1645/norton.animademo D/DepthPageTransformer: 2___0.66597223
05-24 01:50:20.727 1645-1645/norton.animademo D/DepthPageTransformer: 1___-0.23055555
05-24 01:50:20.727 1645-1645/norton.animademo D/DepthPageTransformer: 2___0.76944447
05-24 01:50:20.743 1645-1645/norton.animademo D/DepthPageTransformer: 1___-0.06736111
05-24 01:50:20.743 1645-1645/norton.animademo D/DepthPageTransformer: 2___0.9326389
05-24 01:50:20.760 1645-1645/norton.animademo D/DepthPageTransformer: 1___-0.014583333
05-24 01:50:20.760 1645-1645/norton.animademo D/DepthPageTransformer: 2___0.98541665
05-24 01:50:20.777 1645-1645/norton.animademo D/DepthPageTransformer: 1___-0.0013888889
05-24 01:50:20.777 1645-1645/norton.animademo D/DepthPageTransformer: 2___0.9986111
05-24 01:50:20.794 1645-1645/norton.animademo D/DepthPageTransformer: 1___0.0
05-24 01:50:20.795 1645-1645/norton.animademo D/DepthPageTransformer: 2___1.0
日誌出來這個東西就很好解釋了
可以看見,transformPage這個方法當中的View的值進入,退出的View 來回依次出現的;
前面的數字就是顯示的對應的TextView(這時知道TextView的用處了吧);
對切換而言是有2個對象的,一個是進入的,一個是退出的。
退出的View 的position 是一個 [0,-1] 的值;
進入的View 的position 是一個 [1,0] 的值;
搞懂View和position的關係,現在無論是自定義動畫或者自定義View,都很好處理了。
2. 自定義ViewPagerTransform
下面來看看一個ViewPagerTransforms的開源項目
https://github.com/ToxicBakery/ViewPagerTransforms當中的一些炫酷效果
public class CudeOutTransformer implements ViewPager.PageTransformer {
@Override
public void transformPage(View page, float position) {
page.setPivotX(position < 0f ? page.getWidth() : 0f);
page.setPivotY(page.getHeight() * 0.5f);
page.setRotationY(90f * position);
page.setAlpha(position <= -1f || position >= 1f ? 0f : 1f); // 看不見的view
}
}
公式很簡單就不多解釋了,這裏主要是用了一些三元運算符,
軸轉動和旋轉動畫組合起來效果還不錯。
public class ZoomInTransformer implements ViewPager.PageTransformer{
@Override
public void transformPage(View view, float position) {
final float width = view.getWidth();
view.setRotationX(0);
view.setRotationY(0);
view.setRotation(0);
view.setScaleX(1);
view.setScaleY(1);
view.setPivotX(0);
view.setPivotY(0);
view.setTranslationY(0);
view.setTranslationX(-width * position);
final float scale = position < 0 ? position + 1f : Math.abs(1f - position);
view.setScaleX(scale);
view.setScaleY(scale);
view.setPivotX(view.getWidth() * 0.5f);
view.setPivotY(view.getHeight() * 0.5f);
view.setAlpha(position < -1f || position > 1f ? 0f : 1f - (scale - 1f)); //不可見View
}
}
這個代碼看着挺多的,其實很簡單,主要是一個把View移動到中心位置,然後進入的View放大,退出的View縮小。
總結:其實自定義Viewpager的Transform搞清楚
退出的View 的position 是一個 [0,-1] 的值;
進入的View 的position 是一個 [1,0] 的值;
這一點,就很好處理了,動畫都是有過度值的,由position確定View,再給View設置一個動畫效果,難點在於~ 數學要好!數學要好!