Android动画(ViewHelp/3D旋转)

如果想具体了解Android动画的可参考小编的上一篇博客,在这里我们仅为实现页面的3D旋转效果做一个小的实现。当然,要说这个3D效果与其他3D效果有哪些不同之处呢。也就是拉大了观察者的摄像机与动画之间的距离,避免旋转效果因Y方向上的页面旋转而超出屏幕高度,使整体效果看起来更舒心而已,除此以外还有ViewHelp引用动画的实现。

3D缩放旋转效果

  • 设置摄像头距离
  • 根据中心位置缩放页面视图
  • 绕页面中心Y轴旋转

以上动画效果实现分为以上几个步骤,而其中最需要注意的是旋转角度的设计。如果将页面执行水平旋转180°(比如说0°-180°),那么结果将导致页面的内容也会出现对称的效果,这个可以自行测试下。那么该如何解决这种问题呢?小编的想法是当页面旋转至90°(或者270°)的时候,对应的将当前页面的角度设置为270°(或者90°)。然后再继续执行剩下的90°(180°-90°),最后抵达我们想要的角度为360°(或者0°)。

为了解决上诉的问题,小编试过从ObjectAnimator入手,试着为其添加更多的变化值。如ObjectAnimator.ofFloat(mMainFly, “rotationY”, 0, 90, 270, 360);当然结果肯定是不行的,因为每个角度的变换过程所消耗的时间是等同的,这么做只会导致页面内容的不正常闪烁。所以,最好的方法就是分开执行,且在每个动画单元执行结束后通过setRotationY();的方法设置下个单元的起始角度。下面我们通过Fragment的切换实现上图效果。

@ContentView(R.layout.activity_r3d_frame)
public class R3DFragmentActivity extends FragmentActivity {

    @ViewInject(R.id.r3d_fly_main)
    private FrameLayout mMainFly;

    private R3DFirstFragment mFirstFragment;
    private R3DSecondFragment mSecondFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ViewUtils.inject(this);
        showDefaultFragment();
    }

    /**
     * 默认显示FirstFragment
     */
    public void showDefaultFragment() {
        if (mFirstFragment == null) {
            mFirstFragment = new R3DFirstFragment();
        }
        putFragment(R.id.r3d_fly_main, mFirstFragment, "r3d_fly_main");
    }

    /**
     * 显示SecondFragment
     */
    public void showSecondFragment() {
        if (mSecondFragment == null) {
            mSecondFragment = new R3DSecondFragment();
        }
        showFragmentAdd(R.id.r3d_fly_main, mSecondFragment, "r3d_fly_main");
    }

    /**
     * 为页面跳转及其切换添加3D旋转效果
     */
    public void showCutAnim(final boolean is2Second) {

        final int time = 600;
        final int distance = 15000;
        final int scaleTime = 80;
        final float scale = 0.9f;

        // 设置照相机的距离(避免旋转时高度超出屏幕高度)
        float CameraScale = getResources().getDisplayMetrics().density * distance;
        mMainFly.setCameraDistance(CameraScale);

        ObjectAnimator animatorR1;
        if (is2Second) {
            animatorR1 = ObjectAnimator.ofFloat(mMainFly, "rotationY", 0, 90).setDuration(time / 2);
        } else {
            animatorR1 = ObjectAnimator.ofFloat(mMainFly, "rotationY", 0, -90).setDuration(time / 2);
        }
        ObjectAnimator animatorR2;
        if (is2Second) {
            animatorR2 = ObjectAnimator.ofFloat(mMainFly, "rotationY", 270, 360).setDuration(time / 2);
        } else {
            animatorR2 = ObjectAnimator.ofFloat(mMainFly, "rotationY", -270, -360).setDuration(time / 2);
        }
        ObjectAnimator animatorSX1 = ObjectAnimator.ofFloat(mMainFly, "scaleX", 1.0f, scale).setDuration(scaleTime);
        ObjectAnimator animatorSY1 = ObjectAnimator.ofFloat(mMainFly, "scaleY", 1.0f, scale).setDuration(scaleTime);
        ObjectAnimator animatorSX2 = ObjectAnimator.ofFloat(mMainFly, "scaleX", scale, 1.0f).setDuration(scaleTime);
        ObjectAnimator animatorSY2 = ObjectAnimator.ofFloat(mMainFly, "scaleY", scale, 1.0f).setDuration(scaleTime);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(animatorSX1, animatorSY1);
        animatorSet.playTogether(animatorSX2, animatorSY2);
        animatorSet.play(animatorR1).after(animatorSX1);
        animatorSet.play(animatorR1).before(animatorR2);
        animatorSet.play(animatorR2).before(animatorSX2);
        animatorSet.start();

        animatorR1.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                if (is2Second) {
                    showSecondFragment();
                } else {
                    onBackPressed();
                    mCurrentFragment = mFirstFragment;
                    mMainFly.setRotationY(-270);
                }
            }
        });
    }
}

除了Fragment以外,我们也可以手动修改常用ViewPager,来实现类似上图的动画效果。首先,我们要新建一个.class继承自ViewPager.PageTransformer,重写transformPage(View view, float position);方法来控制当前卡片view的状态,这里需要注意的只是position的变化跟踪,因为ViewHelp的协助来共同完成动画的展现,相比上面的实现,无法为各个动画单元提供各自的执行时长和顺序。最后使用ViewPager.setPageTransformer();方法就可以实现卡片切换的动画效果啦。

public class FilpTransformer implements ViewPager.PageTransformer {

    private Context mContext;
    private static final float MIN_SCALE = 0.9f;

    public FilpTransformer(Context mContext) {
        this.mContext = mContext;
    }

    @Override
    public void transformPage(View view, float position) {

        float pageWidth = view.getMeasuredWidth();
        float pageHeight = view.getMeasuredHeight();

        // 设置照相机的距离(避免旋转时高度超出屏幕高度)
        final int distance = 15000;
        float CameraScale = mContext.getResources().getDisplayMetrics().density * distance;
        view.setCameraDistance(CameraScale);

        // 缩放
        float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
        view.setScaleX(scaleFactor);
        view.setScaleY(scaleFactor);

        // 左侧Page 1 <---- 0 -----> -1 右侧Page
        ViewHelper.setPivotY(view, pageHeight * 0.5f);
        ViewHelper.setRotationY(view, 180f * position);
        if (position <= 0) {
            view.setAlpha(1 - (Math.abs(position)));
            ViewHelper.setPivotX(view, pageWidth);
            if (position <= -1) {
                // 旋转完成将另一个Fragment以90°的位置放置,避免重叠
                ViewHelper.setRotationY(view, 90f * position);
            }
        } else {
            ViewHelper.setPivotX(view, 0);
            if (position == 1) {
                ViewHelper.setRotationY(view, 90f * position);
            }
        }
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值