Android 卡片翻轉動畫效果
APP 開發大概思路是先建立兩個 View 疊在一起,一前一後,前面的顯示,後面的隱藏。 旋轉的時候分三步驟, 第一步將前面的 View 從 0 度旋轉到 90 度, 第二步將前面的 View 隱藏,後面的 View 顯示, 第三將將後面的 View 從 -90 度旋轉到 0 度, 這樣就完成了一次卡片旋轉動畫,下面來看看實際的程式碼該怎麼寫。
第一步:建立佈局檔
# activity_main.xml:建立兩個 View 疊在一起,一前一後,前面的顯示,後面的隱藏。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/viewFront"
android:layout_width="300dp"
android:layout_height="400dp"
android:background="#FF1E88A8"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<Button
android:id="@+id/buttonFront"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="52sp"
android:textStyle="bold"
android:text="正面"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/viewBack"
android:layout_width="300dp"
android:layout_height="400dp"
android:background="#FFE16B8C"
android:visibility="gone"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<Button
android:id="@+id/buttonBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="52sp"
android:textStyle="bold"
android:text="正面"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
第二步:建立動畫檔
# flip_out.xml:從 0 度旋轉到 90 度。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="1000"
android:interpolator="@android:interpolator/accelerate_cubic"
android:propertyName="rotationY"
android:valueFrom="0"
android:valueTo="90" />
</set>
# flip_in.xml:從 -90 度旋轉到 0 度。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="1000"
android:interpolator="@android:interpolator/decelerate_cubic"
android:propertyName="rotationY"
android:valueFrom="-90"
android:valueTo="0" />
</set>
第三步:撰寫動畫程式碼
在程式碼中使用動畫 XML 檔。
viewVisible:旋轉前在正面的 View。
viewInVisible:旋轉前在背面的 View。
private void flipAnimation(Context context, View viewVisible, View viewInVisible) {
Animator animatorFlipOut = AnimatorInflater.loadAnimator(context, R.animator.flip_out);
animatorFlipOut.setTarget(viewVisible);
Animator animatorFlipIn = AnimatorInflater.loadAnimator(context, R.animator.flip_in);
animatorFlipIn.setTarget(viewInVisible);
animatorFlipOut.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
viewVisible.setVisibility(View.GONE);
viewInVisible.setVisibility(View.VISIBLE);
animatorFlipIn.start();
}
});
animatorFlipOut.start();
}
如果不想使用動畫 XML 檔,也可以使用純程式碼達成,請參考以下範例。
private void flipAnimation(View viewVisible, View viewInVisible) {
ObjectAnimator animatorFlipOut = ObjectAnimator.ofFloat(viewVisible, "rotationY", 0f, 90f);
animatorFlipOut.setInterpolator(new AccelerateInterpolator());
animatorFlipOut.setDuration(1000);
ObjectAnimator animatorFlipIn = ObjectAnimator.ofFloat(viewInVisible, "rotationY", -90f, 0f);
animatorFlipIn.setInterpolator(new DecelerateInterpolator());
animatorFlipIn.setDuration(1000);
animatorFlipOut.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
viewVisible.setVisibility(View.GONE);
viewInVisible.setVisibility(View.VISIBLE);
animatorFlipIn.start();
}
});
animatorFlipOut.start();
}
第四步:調整鏡頭位置
基本上做到第三步驟就已經完成了卡片翻轉動畫,但如果還要吹毛求疵的話可以發現,旋轉的時候 View 都跑出整個螢幕畫面了。為了避免這種情況,我們可以為這兩個 View 加入一些相機距離。 根據 Google 文件的說明,如果要指定一個相機距離,並且能在各種密度下呈現相同視覺效果的話,必需使用以下公式:
float scale = context.getResources().getDisplayMetrics().density;
view.setCameraDistance(distance * scale);
稍微調整一下,完整程式碼範例如下:
private void flipAnimation(Context context, View viewVisible, View viewInVisible) {
// 增加相機距離
float scale = context.getResources().getDisplayMetrics().density;
float cameraDist = 10000 * scale;
viewVisible.setCameraDistance(cameraDist);
viewInVisible.setCameraDistance(cameraDist);
// 翻轉動畫
Animator animatorFlipOut = AnimatorInflater.loadAnimator(context, R.animator.flip_out);
animatorFlipOut.setTarget(viewVisible);
Animator animatorFlipIn = AnimatorInflater.loadAnimator(context, R.animator.flip_in);
animatorFlipIn.setTarget(viewInVisible);
animatorFlipOut.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
viewVisible.setVisibility(View.GONE);
viewInVisible.setVisibility(View.VISIBLE);
animatorFlipIn.start();
}
});
animatorFlipOut.start();
}
至此,就全部完成了,可以看出上方動畫在旋轉時,已經不會跑出螢幕了。在公式中的 distance 參數,我是使用 10000,但您可以自行調整這個參數,以達到您想要的效果。
0 則留言