Отображение анимации флип-карты на старом андроиде

Мы все знаем эту статью о том, как создать анимацию "card filp" используя new api . Но как я могу сделать это on apis < 3.0 ?

Обновить:

Пока есть хорошие и простые в использовании библиотеки, такие как android-FlipView, я не думаю, что вам действительно нужно проходить такие жесткие пути …

Solutions Collecting From Web of "Отображение анимации флип-карты на старом андроиде"

Нашел ответ. Если вы хотите сделать флип-анимацию на ALL ANDROID VERSIONS , используйте это:

Файл макета операции:

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main_activity_root" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@android:color/transparent" > <RelativeLayout android:id="@+id/main_activity_card_face" android:layout_width="300dp" android:layout_height="407dp" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:background="@drawable/front" android:clickable="true" android:onClick="onCardClick" android:padding="5dp" > </RelativeLayout> <RelativeLayout android:id="@+id/main_activity_card_back" android:layout_width="300dp" android:layout_height="407dp" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:background="@drawable/back" android:clickable="true" android:onClick="onCardClick" android:visibility="gone" > </RelativeLayout> </RelativeLayout> 

Поскольку файл макета переворачивает две группы представлений, вы можете поместить что-нибудь еще в группу просмотра, и он должен работать. Теперь рассмотрим методы внутри действия, которые обрабатывают вызов флип-анимационного кода:

 public void onCardClick(View view) { flipCard(); } private void flipCard() { View rootLayout = findViewById(R.id.main_activity_root); View cardFace = findViewById(R.id.main_activity_card_face); View cardBack = findViewById(R.id.main_activity_card_back); FlipAnimation flipAnimation = new FlipAnimation(cardFace, cardBack); if (cardFace.getVisibility() == View.GONE) { flipAnimation.reverse(); } rootLayout.startAnimation(flipAnimation); } 

И, наконец, класс FlipAnimation :

 public class FlipAnimation extends Animation { private Camera camera; private View fromView; private View toView; private float centerX; private float centerY; private boolean forward = true; /** * Creates a 3D flip animation between two views. * * @param fromView First view in the transition. * @param toView Second view in the transition. */ public FlipAnimation(View fromView, View toView) { this.fromView = fromView; this.toView = toView; setDuration(700); setFillAfter(false); setInterpolator(new AccelerateDecelerateInterpolator()); } public void reverse() { forward = false; View switchView = toView; toView = fromView; fromView = switchView; } @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); centerX = width/2; centerY = height/2; camera = new Camera(); } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { // Angle around the y-axis of the rotation at the given time // calculated both in radians and degrees. final double radians = Math.PI * interpolatedTime; float degrees = (float) (180.0 * radians / Math.PI); // Once we reach the midpoint in the animation, we need to hide the // source view and show the destination view. We also need to change // the angle by 180 degrees so that the destination does not come in // flipped around if (interpolatedTime >= 0.5f) { degrees -= 180.f; fromView.setVisibility(View.GONE); toView.setVisibility(View.VISIBLE); } if (forward) degrees = -degrees; //determines direction of rotation when flip begins final Matrix matrix = t.getMatrix(); camera.save(); camera.rotateY(degrees); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-centerX, -centerY); matrix.postTranslate(centerX, centerY); } в public class FlipAnimation extends Animation { private Camera camera; private View fromView; private View toView; private float centerX; private float centerY; private boolean forward = true; /** * Creates a 3D flip animation between two views. * * @param fromView First view in the transition. * @param toView Second view in the transition. */ public FlipAnimation(View fromView, View toView) { this.fromView = fromView; this.toView = toView; setDuration(700); setFillAfter(false); setInterpolator(new AccelerateDecelerateInterpolator()); } public void reverse() { forward = false; View switchView = toView; toView = fromView; fromView = switchView; } @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); centerX = width/2; centerY = height/2; camera = new Camera(); } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { // Angle around the y-axis of the rotation at the given time // calculated both in radians and degrees. final double radians = Math.PI * interpolatedTime; float degrees = (float) (180.0 * radians / Math.PI); // Once we reach the midpoint in the animation, we need to hide the // source view and show the destination view. We also need to change // the angle by 180 degrees so that the destination does not come in // flipped around if (interpolatedTime >= 0.5f) { degrees -= 180.f; fromView.setVisibility(View.GONE); toView.setVisibility(View.VISIBLE); } if (forward) degrees = -degrees; //determines direction of rotation when flip begins final Matrix matrix = t.getMatrix(); camera.save(); camera.rotateY(degrees); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-centerX, -centerY); matrix.postTranslate(centerX, centerY); } 

Вот ссылка на оригинальное сообщение: Отображение флип-анимации на старом андроиде

ОБНОВЛЕНИЕ от @FMMobileFelipeMenezes.

Если вы хотите, чтобы анимация с плавным масштабированием перевернулась, измените эту часть кода на (applyTransformation):

 final Matrix matrix = t.getMatrix(); camera.save(); camera.translate(0, 0, Math.abs(degrees)*2); camera.getMatrix(matrix); camera.rotateY(degrees); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-centerX, -centerY); matrix.postTranslate(centerX, centerY); в final Matrix matrix = t.getMatrix(); camera.save(); camera.translate(0, 0, Math.abs(degrees)*2); camera.getMatrix(matrix); camera.rotateY(degrees); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-centerX, -centerY); matrix.postTranslate(centerX, centerY); 

ОБНОВЛЕНИЕ от @Hesam Существует хороший учебник, который я рекомендую прочитать. Хотя это не так хорошо, как учебник для Android, основанный на фрагментах, его нужно читать и использовать, если вы хотите назначить анимацию макетам и представлениям, а также иметь старые API.

Используйте анимацию масштаба Android для имитации 3D-флип

Улучшенный проект по github by @LenaBru

Я использовал код Flextra ниже, и если вы хотите, чтобы анимация с плавным масштабированием отображалась, измените эту часть кода на (applyTransformation):

  final Matrix matrix = t.getMatrix(); camera.save(); camera.translate(0, 0, Math.abs(degrees)*2); camera.getMatrix(matrix); camera.rotateY(degrees); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-centerX, -centerY); matrix.postTranslate(centerX, centerY); в  final Matrix matrix = t.getMatrix(); camera.save(); camera.translate(0, 0, Math.abs(degrees)*2); camera.getMatrix(matrix); camera.rotateY(degrees); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-centerX, -centerY); matrix.postTranslate(centerX, centerY); 

Я играл с этим весь день и, наконец, достиг конечной цели – гладкого карточного флепа, такого как анимация вращения двух видов!

Я разместил демо-проект здесь

 public class FlipAnimation extends Animation { private Camera camera; private View fromView; private View toView; private float centerX; private float centerY; private boolean forward = true; /** * Creates a 3D flip animation between two views. * * @param fromView * First view in the transition. * @param toView * Second view in the transition. */ public FlipAnimation(View fromView, View toView) { this.fromView = fromView; this.toView = toView; setDuration(1500); setFillAfter(false); // setInterpolator(new AccelerateDecelerateInterpolator()); setInterpolator(new LinearInterpolator()); } public void reverse() { if (forward) { View switchView = toView; toView = fromView; fromView = switchView; } forward = false; } @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); centerX = width / 2; centerY = height / 2; camera = new Camera(); } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { // Angle around the y-axis of the rotation at the given time // calculated both in radians and degrees. final double radians = Math.PI * interpolatedTime; float degrees = (float) (180.0 * radians / Math.PI); //scale down the views a bit, so that they would look nice when the rotation begins if (interpolatedTime <= 0.05f) { fromView.setScaleX(1 - interpolatedTime); fromView.setScaleY(1 - interpolatedTime); toView.setScaleX(1 - interpolatedTime); toView.setScaleY(1 - interpolatedTime); } // Once we reach the midpoint in the animation, we need to hide the // source view and show the destination view. We also need to change // the angle by 180 degrees so that the destination does not come in //It is very important to call "toView.bringToFront()" and not play with the // visibility of the views, because if you apply this animation more than once, //the subsequent calls may fail if (interpolatedTime >= 0.5f) { degrees -= 180.f; toView.bringToFront(); //these two lines force a layout redraw ((View)toView.getParent()).requestLayout(); ((View)toView.getParent()).invalidate(); } //scale the views back to their original size (Assuming original size was 1) if (interpolatedTime >= 0.95f) { fromView.setScaleX(interpolatedTime); fromView.setScaleY(interpolatedTime); toView.setScaleX(interpolatedTime); toView.setScaleY(interpolatedTime); } if (forward) degrees = -degrees; // determines direction of rotation when flip // begins final Matrix matrix = t.getMatrix(); camera.save(); camera.translate(0, 0, Math.abs(degrees) * 2); camera.getMatrix(matrix); camera.rotateY(degrees); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-centerX, -centerY); matrix.postTranslate(centerX, centerY); } } в public class FlipAnimation extends Animation { private Camera camera; private View fromView; private View toView; private float centerX; private float centerY; private boolean forward = true; /** * Creates a 3D flip animation between two views. * * @param fromView * First view in the transition. * @param toView * Second view in the transition. */ public FlipAnimation(View fromView, View toView) { this.fromView = fromView; this.toView = toView; setDuration(1500); setFillAfter(false); // setInterpolator(new AccelerateDecelerateInterpolator()); setInterpolator(new LinearInterpolator()); } public void reverse() { if (forward) { View switchView = toView; toView = fromView; fromView = switchView; } forward = false; } @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); centerX = width / 2; centerY = height / 2; camera = new Camera(); } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { // Angle around the y-axis of the rotation at the given time // calculated both in radians and degrees. final double radians = Math.PI * interpolatedTime; float degrees = (float) (180.0 * radians / Math.PI); //scale down the views a bit, so that they would look nice when the rotation begins if (interpolatedTime <= 0.05f) { fromView.setScaleX(1 - interpolatedTime); fromView.setScaleY(1 - interpolatedTime); toView.setScaleX(1 - interpolatedTime); toView.setScaleY(1 - interpolatedTime); } // Once we reach the midpoint in the animation, we need to hide the // source view and show the destination view. We also need to change // the angle by 180 degrees so that the destination does not come in //It is very important to call "toView.bringToFront()" and not play with the // visibility of the views, because if you apply this animation more than once, //the subsequent calls may fail if (interpolatedTime >= 0.5f) { degrees -= 180.f; toView.bringToFront(); //these two lines force a layout redraw ((View)toView.getParent()).requestLayout(); ((View)toView.getParent()).invalidate(); } //scale the views back to their original size (Assuming original size was 1) if (interpolatedTime >= 0.95f) { fromView.setScaleX(interpolatedTime); fromView.setScaleY(interpolatedTime); toView.setScaleX(interpolatedTime); toView.setScaleY(interpolatedTime); } if (forward) degrees = -degrees; // determines direction of rotation when flip // begins final Matrix matrix = t.getMatrix(); camera.save(); camera.translate(0, 0, Math.abs(degrees) * 2); camera.getMatrix(matrix); camera.rotateY(degrees); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-centerX, -centerY); matrix.postTranslate(centerX, centerY); } } 

И назовите это так

 import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.FragmentActivity; import android.view.View; import android.view.View.OnClickListener; import android.widget.Toast; public class MainActivity extends FragmentActivity { private boolean showingBack; private FragmentLeft left = new FragmentLeft(); private FragmentRight right = new FragmentRight(); private Context context; private Handler handler; private FlipAnimation flipAnimation; private FlipAnimation backFlip; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); context = this; handler = new Handler(getMainLooper()); getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, right, "fragmentRight").commit(); getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, left, "fragmentLeft").commit(); findViewById(R.id.flip).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { flipAnimation = new FlipAnimation(left.getView(), right.getView()); backFlip = new FlipAnimation(left.getView(), right.getView()); handler.removeCallbacks(rotate); handler.postDelayed(rotate, 100); } }); } private Runnable rotate = new Runnable() { @Override public void run() { //put a variable showingBack, do not rely on view properties to flip if (!showingBack) { //very important to flip both views, so that when the //left view goes to back and right view goes to front, //the right view finishes the rotation left.getView().startAnimation(flipAnimation); right.getView().startAnimation(flipAnimation); Toast.makeText(context, "flip", Toast.LENGTH_LONG).show(); showingBack = true; } else { showingBack = false; backFlip.reverse(); Toast.makeText(context, "backflip", Toast.LENGTH_LONG).show(); //very important to flip both views, so that when the //right view goes to back and right view goes to front, //the left view finishes the rotation left.getView().startAnimation(backFlip); right.getView().startAnimation(backFlip); } } }; } 

Это фрагменты

 import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class FragmentRight extends Fragment { @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_right, container,false); } } import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class FragmentLeft extends Fragment { @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_left, container,false); } } 

И, наконец, сам взгляд

activity_main.xml

 <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" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:background="#ff151515" tools:context="com.example.flipviewtest.MainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> <FrameLayout android:id="@+id/fragment_container" android:layout_width="200dp" android:layout_height="200dp" android:layout_centerInParent="true" > </FrameLayout> <Button android:id="@+id/flip" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:text="flip" /> </RelativeLayout> 

fragment_left.xml

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="#ffff0000" > <View android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ff0ffff0" android:layout_margin="20dp" /> </LinearLayout> 

fragment_right.xml

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ff00ff00" android:orientation="vertical" > <View android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="10dp" android:background="#ff0000ff" /> </LinearLayout> 

Обратите внимание на некоторые из кода, взятого из ответов Flextra's и @FMMobileFelipeMenezes

Существует хороший учебник, который я рекомендую прочитать. Хотя это не так хорошо, как учебник для Android, основанный на фрагментах, его нужно читать и использовать, если вы хотите назначить анимацию макетам и представлениям, а также иметь старые API.

Используйте анимацию масштаба Android для имитации 3D-флип