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

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

Обновление:

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


person Alexander.Iljushkin    schedule 16.04.2013    source источник


Ответы (4)


Нашел ответ. Если вы хотите сделать флип-анимацию на 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);
    }

Вот ссылка на оригинальный пост: Отображение анимации переворота карты на старом Android

ОБНОВЛЕНИЕ от @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);

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

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

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

person Alexander.Iljushkin    schedule 16.04.2013
comment
Большой! Спасибо за этот замечательный код. Только один вопрос: как я могу повернуться к фрагменту, который не входит в текущую активность? Я могу получить представление из фрагмента с помощью Fragment.getView(), но затем возникает ошибка, если я запускаю анимацию. - person Cilenco; 19.05.2013
comment
Cilenco, попробуйте переопределить класс фрагмента и поместить этот код внутрь. Или создайте прослушиватель действий. Во всяком случае, я не уверен, что это поможет. С фрагментами пока не разобрался. - person Alexander.Iljushkin; 20.05.2013
comment
Спасибо, чувак.. +1.. Даже внутри Фрагмента тоже работает.. Так держать. :) - person MS.; 05.06.2013
comment
я хочу перевернуть 2 изображения в одном представлении, то есть в одном изображении, пожалуйста, помогите? - person Nilesh Verma; 07.08.2013
comment
@NileshVerma, почему бы и нет. просто добавьте два изображения вместе внутри android:id="@+id/main_activity_card_face" или android:id="@+id/main_activity_card_back" - person Alexander.Iljushkin; 07.08.2013
comment
@A.P нет, я не могу, потому что я делаю кое-что еще, используя это одно изображение, пожалуйста, помогите перевернуть два изображения в одном изображении. - person Nilesh Verma; 07.08.2013
comment
@NileshVerma, пожалуйста, предоставьте более подробную информацию о том, как и что вы пытаетесь сделать. Пока я не понимаю, что именно вы хотите. - person Alexander.Iljushkin; 08.08.2013
comment
Привет, может ли кто-нибудь сказать мне, как использовать его с элементом списка Android ListView с видом спереди и сзади? в пользовательском адаптере - person Bhavik Mehta; 23.03.2015
comment
@BhavikMehta Flip Animation теперь доступна при использовании официальной Android Studio. Вы можете скачать Android Studio бесплатно со страниц Google Android. Когда вы создаете новый проект, вас спросят о желаемом типе примера проекта. Выберите тип переворота. Выберите желаемый минимальный API, т.е. 2, если вы выберете 2x уровень API, новый проект будет сгенерирован с использованием библиотеки поддержки и большого количества полезного кода, который вы должны написать сами. Чтобы заставить его работать, просто создайте свой собственный класс списка и примените к нему аналогичный код. вам следует подумать о том, как применить подобную анимацию активности - person Alexander.Iljushkin; 23.03.2015
comment
@BhavikMehta также ищет что-то подобное stackoverflow. ком/вопросы/27626750/ - person Alexander.Iljushkin; 23.03.2015
comment
Вы спасли мою жизнь! Большое спасибо! ты живешь 100 лет! может быть больше :D - person Darshn; 24.11.2015
comment
@Darsh, в новой Android Studio теперь есть новый мастер, в котором вы можете выбрать полное перелистывание прямо из коробки. Просто загрузите Android Studio из Google. - person Alexander.Iljushkin; 25.11.2015
comment
Ницца! почему-то для меня флип-идентификатор плохо отображается вверху и внизу экрана, углы и центр не выровнены во время флипа, есть идеи? - person Elisabeth; 08.08.2017
comment
@Elisa, загрузите новую студию для Android, есть встроенный макет флип-представления из мастера создания нового проекта (насколько я помню). Также посмотрите описание вопроса, там есть ссылка на библиотеку flipview - person Alexander.Iljushkin; 08.08.2017
comment
@Александр.Ильюшкин Спасибо! Я не заметил макет ViewFlipper. - person Elisabeth; 09.08.2017
comment
Это потрясающе. Работает намного лучше, чем даже учебник Google. Они должны просто связать свой учебник с этим ответом. - person Trevor Wood; 12.10.2017

Я использовал код 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);
person Felipe FMMobile    schedule 07.11.2013

Я играл с этим весь день и, наконец, добился конечной цели - плавного переворачивания карты, похожего на анимацию вращения двух видов!

Демонстрационный проект я разместил здесь

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>

фрагмент_левый.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>

фрагмент_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 и @FMMobileFelipeMenezes

person Lena Bru    schedule 11.08.2014
comment
можно ли изменить цвет фона (или изображение) во время анимации? - person David; 14.07.2016

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

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

person Hesam    schedule 14.10.2013