一个比较有趣的 Android 动画效果

先来看一下效果

技术分享

分析实现原理:

这里主要知识点是对动画的使用,原理页很简单,在一个 Activity 中布局两个 Fragment,不用 fragment 也行,但是在同一个 xml 中代码量就会比较庞大;初始化的时候让第二个 Fagment 移动到底部隐藏起来,就是刚启动应用时的界面,点击开始之后,执行相应的动画,第一个 Fragment 的 X 和 Y都同时缩小,并且一开始让 X旋转25度,等一定时间,让 X旋转的角度复原,此过程就是 Fragment 的向后移动的动画过程,同时有一个黑色的背景设置它的透明度,从全透到0.5f;第二个Fragment动画就非常简单,单纯的向下和向上移动。

这里就贴一部分代码出来,有兴趣了解的可以直接下载源码下来研究。
贴代码过程:
向后移动动画

        mHoverView.setClickable(true);
        /*设置背景透明度动画*/
        ObjectAnimator animator = ObjectAnimator.ofFloat(mHoverView, "alpha", 0, 0.5f);
        /*放小X 的动画*/
        ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(mOriginalView, "scaleX", 1.0f, .8f);
        /*放小Y 的 动画*/
        ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(mOriginalView, "scaleY", 1.0f, .8f);
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(animator, scaleXAnim, scaleYAnim);
        animatorSet.setDuration(350);
        animatorSet.start();
        /*先让X 旋转20度的动画*/
        ObjectAnimator transX = ObjectAnimator.ofFloat(mOriginalView,"RotationX",20.0f);
        transX.setDuration(150);
        transX.start();
        /*等一定时间让X 旋转角度复位*/
        ObjectAnimator resumeX = ObjectAnimator.ofFloat(mOriginalView,"RotationX",0.0f);
        resumeX.setDuration(200);
        resumeX.setStartDelay(150);
        resumeX.start();

知道了后退的动画,反过来的动画就很好理解了

        mHoverView.setClickable(false);
        ObjectAnimator animator = ObjectAnimator.ofFloat(mHoverView, "alpha", 0.5f, 0);
        ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(mOriginalView, "scaleX", .8f, 1.0f);
        ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(mOriginalView, "scaleY", .8f, 1.0f);
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(animator, scaleXAnim, scaleYAnim);
        animatorSet.setDuration(350);
        animatorSet.start();
        ObjectAnimator transX = ObjectAnimator.ofFloat(mOriginalView,"RotationX",20.0f);
        transX.setDuration(150);
        transX.start();
        ObjectAnimator resumeX = ObjectAnimator.ofFloat(mOriginalView,"RotationX",0.0f);
        resumeX.setDuration(200);
        resumeX.setStartDelay(150);
        resumeX.start();

以下是第二个 Fragment 上下移动的动画

/**
 * Created by moon.zhong on 2015/4/12.
 */
public class AnimationCompat implements Runnable {
    private Scroller mScroller;

    private View mAnimationView;
    private int mViewHeight;

    private final int DURATION = 350;

    public AnimationCompat(Context context, View view) {
        mScroller = new Scroller(context, new LinearInterpolator());
        mAnimationView = view;
        mViewHeight = mAnimationView.getMeasuredHeight();
        if (mViewHeight == 0) {
            mAnimationView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    mAnimationView.getViewTreeObserver().removeOnPreDrawListener(this);
                    mViewHeight = mAnimationView.getMeasuredHeight();
                    return false;
                }
            });
        }
    }

    public void startHideAnimation(boolean scrollUp) {
        int dy = (int) ViewCompat.getTranslationY(mAnimationView) + mViewHeight;
        if (!scrollUp) {
            dy = (int) ViewCompat.getTranslationY(mAnimationView) - mViewHeight;
        }
        int duration = (int) Math.abs(DURATION * ViewCompat.getTranslationY(mAnimationView) * 1.0f / mViewHeight);
        duration = duration == 0 ? DURATION : duration;
        mScroller.startScroll(0, (int) ViewCompat.getTranslationY(mAnimationView), 0, -dy, duration);
        ViewCompat.postOnAnimation(mAnimationView, this);
    }

    public void startShawAnimation() {
        int dy = (int) ViewCompat.getTranslationY(mAnimationView);
        int duration = (int) Math.abs(DURATION);
        mScroller.startScroll(0, dy, 0, -dy, duration);
        ViewCompat.postOnAnimation(mAnimationView, this);
    }

    public void abortAnimation() {
        mScroller.abortAnimation();
    }

    @Override
    public void run() {
        if (mScroller.computeScrollOffset()) {

            ViewCompat.postOnAnimation(mAnimationView, this);
            ViewCompat.setTranslationY(mAnimationView, mScroller.getCurrY());

        }

    }
}

MainActivity的 xml 页贴出来,因为涉及到 fragment 的布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/black"
    android:id="@+id/id_anim_content">

    <fragment
        class="com.test.gyzhong.funanimator.OriginalFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/id_original_fragment"
        />
    <View
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/id_hover_view"
        android:background="@android:color/black"
        android:alpha="0"/>
    <RelativeLayout
        android:id="@+id/id_bottom_view"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:background="@android:color/white"
        android:layout_alignParentBottom="true"
        android:layout_marginRight="50dp"
        android:layout_marginLeft="50dp">
        <fragment        class="com.test.gyzhong.funanimator.AnimFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/id_fragment_instruct"
            />
        </RelativeLayout>
</RelativeLayout>

这里如果把两个 Fragment 的布局全部放到这一个布局文件中,代码将会非常难看,全部集中在一个文件中!

总结:

没有总结,就是要熟运用属性动画!

demo 源码

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。