直接看圖:
實現此功能,會用到屬性動畫;
但是具體做起來,有兩種途徑:
1)純java代碼來寫:
1 package com.example.cardrotation; 2 3 import android.animation.Animator; 4 import android.animation.AnimatorListenerAdapter; 5 import android.animation.AnimatorSet; 6 import android.animation.ObjectAnimator; 7 import android.os.Bundle; 8 import android.support.v7.app.AppCompatActivity; 9 import android.view.View; 10 import android.widget.FrameLayout; 11 12 /** 13 * 旋轉卡片特效 14 * 第1種寫法 15 * <p> 16 * 用純java代碼來寫動畫特效以及 執行動畫 17 */ 18 public class MainActivity2 extends AppCompatActivity { 19 20 private FrameLayout mFlCardBack, mFlCardFront, mFlContainer; 21 22 @Override 23 protected void onCreate(Bundle savedInstanceState) { 24 super.onCreate(savedInstanceState); 25 setContentView(R.layout.activity_main); 26 27 mFlCardBack = findViewById(R.id.fl_back); 28 mFlCardFront = findViewById(R.id.fl_front); 29 mFlContainer = findViewById(R.id.main_fl_container); 30 mFlContainer.setOnClickListener(new View.OnClickListener() { 31 @Override 32 public void onClick(View v) { 33 flipCard(); 34 } 35 }); 36 37 initAnimatorSet(); 38 setCameraDistance(); // 設置鏡頭距離 39 } 40 41 // 改變視角距離, 貼近屏幕,這個必須設置,因為如果不這么做,沿着Y軸旋轉的過程中有可能產生超出屏幕的3D效果。 42 private void setCameraDistance() { 43 int distance = 16000; 44 float scale = getResources().getDisplayMetrics().density * distance; 45 mFlCardFront.setCameraDistance(scale); 46 mFlCardBack.setCameraDistance(scale); 47 } 48 49 private boolean mIsShowBack = false; 50 51 // 翻轉卡片 52 public void flipCard() { 53 // 正面朝上 54 if (!mIsShowBack) { 55 inSet.setTarget(mFlCardBack); 56 outSet.setTarget(mFlCardFront); 57 mIsShowBack = true; 58 } else { // 背面朝上 59 inSet.setTarget(mFlCardFront); 60 outSet.setTarget(mFlCardBack); 61 mIsShowBack = false; 62 } 63 inSet.start(); 64 outSet.start(); 65 } 66 67 AnimatorListenerAdapter animatorListenerAdapter = new AnimatorListenerAdapter() { 68 @Override 69 public void onAnimationStart(Animator animation) { 70 super.onAnimationStart(animation); 71 mFlContainer.setClickable(false);//在動畫執行過程中,不許允許接收點擊事件 72 } 73 74 @Override 75 public void onAnimationEnd(Animator animation) { 76 super.onAnimationEnd(animation); 77 mFlContainer.setClickable(true);//在動畫執行過程中,不許允許接收點擊事件 78 } 79 }; 80 81 private AnimatorSet inSet, outSet; 82 83 private void initAnimatorSet() { 84 inSet = new AnimatorSet(); 85 ObjectAnimator animator = ObjectAnimator.ofFloat(null, "rotationY", -180f, 0f); 86 animator.setDuration(500); 87 animator.setStartDelay(0); 88 ObjectAnimator animator2 = ObjectAnimator.ofFloat(null, "alpha", 0.0f, 1f); 89 animator2.setStartDelay(250); 90 animator2.setDuration(0); 91 inSet.playTogether(animator, animator2); 92 inSet.addListener(animatorListenerAdapter); 93 94 outSet = new AnimatorSet(); 95 ObjectAnimator animator_ = ObjectAnimator.ofFloat(null, "rotationY", 0, 180f); 96 animator_.setDuration(500); 97 animator_.setStartDelay(0); 98 ObjectAnimator animator2_ = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f); 99 animator2_.setStartDelay(250); 100 animator2_.setDuration(0); 101 outSet.playTogether(animator_, animator2_); 102 outSet.addListener(animatorListenerAdapter); 103 } 104 105 }
2) 用 animator.xml來配置動畫特效,然后在java代碼中執行動畫
1 package com.example.cardrotation; 2 3 import android.animation.Animator; 4 import android.animation.AnimatorInflater; 5 import android.animation.AnimatorListenerAdapter; 6 import android.animation.AnimatorSet; 7 import android.support.v7.app.AppCompatActivity; 8 import android.os.Bundle; 9 import android.view.View; 10 import android.widget.FrameLayout; 11 12 /** 13 * 旋轉卡片特效 14 * 第2種寫法 15 * 16 * 用animator.xml的配置來描述動畫特效 17 * 在代碼中,執行動畫 18 * 19 */ 20 public class MainActivity extends AppCompatActivity { 21 22 private FrameLayout mFlCardBack, mFlCardFront, mFlContainer; 23 24 @Override 25 protected void onCreate(Bundle savedInstanceState) { 26 super.onCreate(savedInstanceState); 27 setContentView(R.layout.activity_main); 28 29 mFlCardBack = findViewById(R.id.fl_back); 30 mFlCardFront = findViewById(R.id.fl_front); 31 mFlContainer = findViewById(R.id.main_fl_container); 32 mFlContainer.setOnClickListener(new View.OnClickListener() { 33 @Override 34 public void onClick(View v) { 35 flipCard(); 36 } 37 }); 38 39 initAnimatorSet(); // 設置動畫 40 setCameraDistance(); // 設置鏡頭距離 41 } 42 43 // 改變視角距離, 貼近屏幕,這個必須設置,因為如果不這么做,沿着Y軸旋轉的過程中有可能產生超出屏幕的3D效果。 44 private void setCameraDistance() { 45 int distance = 16000; 46 float scale = getResources().getDisplayMetrics().density * distance; 47 mFlCardFront.setCameraDistance(scale); 48 mFlCardBack.setCameraDistance(scale); 49 } 50 51 private boolean mIsShowBack = false; 52 53 // 翻轉卡片 54 public void flipCard() { 55 // 正面朝上 56 if (!mIsShowBack) { 57 mRightOutSet.setTarget(mFlCardFront); 58 mLeftInSet.setTarget(mFlCardBack); 59 mIsShowBack = true; 60 } else { // 背面朝上 61 mRightOutSet.setTarget(mFlCardBack); 62 mLeftInSet.setTarget(mFlCardFront); 63 mIsShowBack = false; 64 } 65 mRightOutSet.start(); 66 mLeftInSet.start(); 67 } 68 69 private AnimatorSet mRightOutSet, mLeftInSet; 70 AnimatorListenerAdapter animatorListenerAdapter = new AnimatorListenerAdapter() { 71 @Override 72 public void onAnimationStart(Animator animation) { 73 super.onAnimationStart(animation); 74 mFlContainer.setClickable(false);//在動畫執行過程中,不許允許接收點擊事件 75 } 76 77 @Override 78 public void onAnimationEnd(Animator animation) { 79 super.onAnimationEnd(animation); 80 mFlContainer.setClickable(true);//在動畫執行過程中,不許允許接收點擊事件 81 } 82 }; 83 84 85 private void initAnimatorSet() { 86 mRightOutSet = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.anim_out); 87 mLeftInSet = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.anim_in); 88 89 // 設置點擊事件 90 mRightOutSet.addListener(animatorListenerAdapter); 91 mLeftInSet.addListener(animatorListenerAdapter); 92 } 93 }
這里用到了xml配置,所以必須在res中寫xml
下面貼出anim_in.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 這里做個說明- 用XML來配置動畫效果,下面這種平行的寫法其實是讓旋轉,和透明動畫 同時執行, startOffset是執行延時,對應ObjectAnimator的 setStartDelay(long startDelay) 方法 --> <!--旋轉--> <objectAnimator android:duration="500" android:propertyName="rotationY" android:valueFrom="-180" android:valueTo="0" /> <!--出現--> <objectAnimator android:duration="0" android:propertyName="alpha" android:startOffset="250" android:valueFrom="0.0" android:valueTo="1.0" /> <!-- 所以說這個startOffSet的意思就是,這個動畫延遲多久ms以后執行 --> </set>
和anim_out.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <!--旋轉--> <objectAnimator android:duration="500" android:propertyName="rotationY" android:valueFrom="0" android:valueTo="180" /> <!--消失--> <objectAnimator android:duration="0" android:propertyName="alpha" android:startOffset="250" android:valueFrom="1.0" android:valueTo="0.0" /> </set>
OK,關鍵代碼上面已經給出。
下面是公共部分布局的代碼:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main_fl_container" android:layout_width="match_parent" android:layout_height="match_parent"> <include layout="@layout/cell_card_back" /> <include layout="@layout/cell_card_front" /> </FrameLayout>
卡片反面cell_card_back.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fl_back" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="20dp"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorPrimary" android:gravity="center" android:text="反面" android:textColor="@color/colorAccent" android:textSize="30sp" /> </FrameLayout>
卡片正面 cell_card_front.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="20dp" android:id="@+id/fl_front"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/darker_gray" android:gravity="center" android:text="正面" android:textColor="@color/colorPrimary" android:textSize="30sp" /> </FrameLayout>
OK,完事。
所有的動畫特效基本都有這兩種寫法。
具體用什么,看心情吧。
用純java,可能api查起來方便一點,畢竟xml寫配置,不能alt點進去看屬性說明。
用xml的話,可能在代碼端就簡潔一點,屬性,自己想辦法上網查好了。
就這樣了·····