如果想具體了解Android動畫的可參考小編的上一篇部落格,在這裡我們僅為實作頁面的3D旋轉效果做一個小的實作。當然,要說這個3D效果與其他3D效果有哪些不同之處呢。也就是拉大了觀察者的錄影機與動畫之間的距離,避免旋轉效果因Y方向上的頁面旋轉而超出螢幕高度,使整體效果看起來更舒心而已,除此以外還有ViewHelp引用動畫的實作。
- 設定攝像頭距離
- 根據中心位置縮放頁面視圖
- 繞頁面中心Y軸旋轉
以上動畫效果實作分為以上幾個步驟,而其中最需要注意的是旋轉角度的設計。如果将頁面執行水準旋轉180°(比如說0°-180°),那麼結果将導緻頁面的内容也會出現對稱的效果,這個可以自行測試下。那麼該如何解決這種問題呢?小編的想法是當頁面旋轉至90°(或者270°)的時候,對應的将目前頁面的角度設定為270°(或者90°)。然後再繼續執行剩下的90°(180°-90°),最後抵達我們想要的角度為360°(或者0°)。
為了解決上訴的問題,小編試過從ObjectAnimator入手,試着為其添加更多的變化值。如ObjectAnimator.ofFloat(mMainFly, “rotationY”, 0, 90, 270, 360);當然結果肯定是不行的,因為每個角度的變換過程所消耗的時間是等同的,這麼做隻會導緻頁面内容的不正常閃爍。是以,最好的方法就是分開執行,且在每個動畫單元執行結束後通過setRotationY();的方法設定下個單元的起始角度。下面我們通過Fragment的切換實作上圖效果。
@ContentView(R.layout.activity_r3d_frame)
public class R3DFragmentActivity extends FragmentActivity {
@ViewInject(R.id.r3d_fly_main)
private FrameLayout mMainFly;
private R3DFirstFragment mFirstFragment;
private R3DSecondFragment mSecondFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewUtils.inject(this);
showDefaultFragment();
}
/**
* 預設顯示FirstFragment
*/
public void showDefaultFragment() {
if (mFirstFragment == null) {
mFirstFragment = new R3DFirstFragment();
}
putFragment(R.id.r3d_fly_main, mFirstFragment, "r3d_fly_main");
}
/**
* 顯示SecondFragment
*/
public void showSecondFragment() {
if (mSecondFragment == null) {
mSecondFragment = new R3DSecondFragment();
}
showFragmentAdd(R.id.r3d_fly_main, mSecondFragment, "r3d_fly_main");
}
/**
* 為頁面跳轉及其切換添加3D旋轉效果
*/
public void showCutAnim(final boolean is2Second) {
final int time = ;
final int distance = ;
final int scaleTime = ;
final float scale = f;
// 設定照相機的距離(避免旋轉時高度超出螢幕高度)
float CameraScale = getResources().getDisplayMetrics().density * distance;
mMainFly.setCameraDistance(CameraScale);
ObjectAnimator animatorR1;
if (is2Second) {
animatorR1 = ObjectAnimator.ofFloat(mMainFly, "rotationY", , ).setDuration(time / );
} else {
animatorR1 = ObjectAnimator.ofFloat(mMainFly, "rotationY", , -).setDuration(time / );
}
ObjectAnimator animatorR2;
if (is2Second) {
animatorR2 = ObjectAnimator.ofFloat(mMainFly, "rotationY", , ).setDuration(time / );
} else {
animatorR2 = ObjectAnimator.ofFloat(mMainFly, "rotationY", -, -).setDuration(time / );
}
ObjectAnimator animatorSX1 = ObjectAnimator.ofFloat(mMainFly, "scaleX", f, scale).setDuration(scaleTime);
ObjectAnimator animatorSY1 = ObjectAnimator.ofFloat(mMainFly, "scaleY", f, scale).setDuration(scaleTime);
ObjectAnimator animatorSX2 = ObjectAnimator.ofFloat(mMainFly, "scaleX", scale, f).setDuration(scaleTime);
ObjectAnimator animatorSY2 = ObjectAnimator.ofFloat(mMainFly, "scaleY", scale, f).setDuration(scaleTime);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(animatorSX1, animatorSY1);
animatorSet.playTogether(animatorSX2, animatorSY2);
animatorSet.play(animatorR1).after(animatorSX1);
animatorSet.play(animatorR1).before(animatorR2);
animatorSet.play(animatorR2).before(animatorSX2);
animatorSet.start();
animatorR1.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (is2Second) {
showSecondFragment();
} else {
onBackPressed();
mCurrentFragment = mFirstFragment;
mMainFly.setRotationY(-);
}
}
});
}
}
除了Fragment以外,我們也可以手動修改常用ViewPager,來實作類似上圖的動畫效果。首先,我們要建立一個.class繼承自ViewPager.PageTransformer,重寫transformPage(View view, float position);方法來控制目前卡片view的狀态,這裡需要注意的隻是position的變化跟蹤,因為ViewHelp的協助來共同完成動畫的展現,相比上面的實作,無法為各個動畫單元提供各自的執行時長和順序。最後使用ViewPager.setPageTransformer();方法就可以實作卡片切換的動畫效果啦。
public class FilpTransformer implements ViewPager.PageTransformer {
private Context mContext;
private static final float MIN_SCALE = f;
public FilpTransformer(Context mContext) {
this.mContext = mContext;
}
@Override
public void transformPage(View view, float position) {
float pageWidth = view.getMeasuredWidth();
float pageHeight = view.getMeasuredHeight();
// 設定照相機的距離(避免旋轉時高度超出螢幕高度)
final int distance = ;
float CameraScale = mContext.getResources().getDisplayMetrics().density * distance;
view.setCameraDistance(CameraScale);
// 縮放
float scaleFactor = Math.max(MIN_SCALE, - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
// 左側Page 1 <---- 0 -----> -1 右側Page
ViewHelper.setPivotY(view, pageHeight * f);
ViewHelper.setRotationY(view, f * position);
if (position <= ) {
view.setAlpha( - (Math.abs(position)));
ViewHelper.setPivotX(view, pageWidth);
if (position <= -) {
// 旋轉完成将另一個Fragment以90°的位置放置,避免重疊
ViewHelper.setRotationY(view, f * position);
}
} else {
ViewHelper.setPivotX(view, );
if (position == ) {
ViewHelper.setRotationY(view, f * position);
}
}
}
}