【问题标题】:Displaying card flip animation on old android在旧 android 上显示卡片翻转动画
【发布时间】:2013-04-08 11:33:30
【问题描述】:

我们都知道article 如何使用new api 创建"card filp" 动画。 但是我怎样才能做到这一点on apis < 3.0

更新:

只要有像android-FlipView这样好的好用的库,我认为你真的不需要自己做这样的动画。

【问题讨论】:

    标签: android api flip nineoldandroids


    【解决方案1】:

    找到了答案。如果你想在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>
    

    当布局文件翻转两个视图组时,您可以在视图组中放置任何其他内容,它应该可以工作。现在让我们看看 Activity 中处理调用翻转动画代码的方法:

    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);
        }
    

    这里是原始帖子的链接: Displaying card flip animation on old 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 我建议阅读它的好教程。尽管它不如基于 Fragment 的 Android 教程那么好,但如果您想将动画分配给布局和视图以及在旧 API 上使用它,那么它值得一读并很有用。

    Use Android's scale animation to simulate a 3D flip

    Improved project on github by @LenaBru

    【讨论】:

    • 太棒了!为这个很棒的代码加油。只有一个问题:如何旋转到当前活动之外的片段?我可以使用Fragment.getView() 从片段中获取视图,但是如果我启动动画则会出现错误。
    • Cilenco,尝试重新定义片段类并将这段代码放入其中。或者创建一个动作监听器。无论如何,我不太确定这是否有帮助。还没有处理碎片。
    • 谢谢老兄..+1.. 即使它也在 Fragment 中工作.. 继续。:)
    • 我想在单个视图中翻转 2 个图像,即在单个图像视图中,请帮忙?
    • @NileshVerma 为什么不呢。只需在 android:id="@+id/main_activity_card_face"android:id="@+id/main_activity_card_back" 内添加两个图像视图
    【解决方案2】:

    我使用了下面的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);
    

    【讨论】:

      【解决方案3】:

      我玩了一天,终于达到了终极目标——两个视图的流畅的翻牌式旋转动画!

      我放了demo项目here

      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 和 @FMMobileFelipeMenezes 答案的代码

      【讨论】:

      • 是否可以在动画期间更改背景颜色(或图像)?
      【解决方案4】:

      我推荐阅读它的好教程。尽管它不如基于 Fragment 的 Android 教程那么好,但如果您想将动画分配给布局和视图以及在旧 API 上使用它,那么它值得一读并很有用。

      Use Android's scale animation to simulate a 3D flip

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-11-22
        • 2014-03-03
        • 1970-01-01
        • 1970-01-01
        • 2018-02-17
        • 2013-12-21
        • 2017-10-20
        相关资源
        最近更新 更多