MTransition使用示例、Q&A

上一篇文章,我简单地介绍了MTransition,请查看链接:MTransition介绍和使用 ---- 一个页面切换动画库(Android)

这里我将较为详细地用示例代码说明下MTransition的使用。


在下面的代码示例中,我们都假设需要用MTransition完成一个从ActivityA到ActivityB的过场动画,并称ActivityA为FromPage,称ActivityB为ToPage;

基础用法(请参考Demo0、Demo1、Demo2)

ezgif.com-video-to-gif (5).gif

Step1、
在FromPage打开ToPage之前,需要创建一个MTransition实例,并通过setContainer()告诉FromPage的最外层父容器View是什么,和通过addTransitionView()设置FromPage中参与过场动画的View(参考代码Example2EntryActivity.java):

final MTransition transition = MTransitionManager.getInstance().createTransition("example");
transition.fromPage().setContainer(mPage, new ITransitPrepareListener() {
    @Override
    public void onPrepare(MTransitionView container) {
        transition.fromPage().addTransitionView("icon", view.findViewById(R.id.item_icon));
        transition.fromPage().addTransitionView("name", view.findViewById(R.id.item_name));
        transition.fromPage().addTransitionView("snapshot", view.findViewById(R.id.item_snapshot));
        transition.fromPage().addTransitionView("container", mPage);
    }
});

Step2、
(非Activity的情况可以忽略这一步)在FromPage打开ToPage,一般情况下,FromPage和ToPage都是Activity,这时需要在startActivity()之后,紧接调用以下代码:

startActivity(intent);
MTranstionUtil.removeActivityAnimation(YourActivity.this);

这一步的作用是,Android默认会给Acitivty一个进场和退场的动画,调用这个代码可以暂时移除Android的默认动画,防止和MTransition的动画冲突;

Step3、
在打开ToPage之后,并且在ToPage显示之前(注意,一定要在显示之前,这个时机一般是在View创建完成之后,例如onCreate等),获取在FromPage创建的MTransition实例,同样地,告诉ToPage的最外层父容器View是什么,和通过addTransitionView()设置ToPage中参与过场动画的View;

同时这里可以获取FromPage和ToPage所有参与动画的View,通过"alpha()、translate()、transitTo()"等接口,表明这些View要如何做动画;
也可以通过"above()、below()"接口去调整View的显示层级(参考代码Example2DetailActivity.java):

final MTransition transition = MTransitionManager.getInstance().getTransition("example");
transition.toPage().setContainer(mAppDetailPage, new ITransitPrepareListener() {
    @Override
    public void onPrepare(MTransitionView container) {
        container.alpha(0f, 1f);
        MTransitionView icon = transition.toPage().addTransitionView("icon", mAppDetailPage.mImage);
        MTransitionView name = transition.toPage().addTransitionView("name", mAppDetailPage.mName);
        transition.fromPage().getTransitionView("icon").above(icon).transitTo(icon, true);
transition.fromPage().getTransitionView("name").above(name).transitTo(name);
    }
});

Step4、
最后,同样是在ToPage显示之前,调用MTransition.start()方法,去启动整个过场动画:

transition.setDuration(500);        // 整个动画时长
transition.start();

如果有需要,你可以设置监听器,去监听过场动画的过程:

transition.setOnTransitListener(new TransitListenerAdapter() {
    @Override
    public void onTransitEnd(MTransition transition, boolean reverse) {
       // do somthing
    }
});

反向动画

ezgif.com-gif-maker.gif

MTransition提供了reverse()接口,可以实现过场动画原路径反向播放,方便你在ToPage返回FromPage的时候调用:

    @Override
    public void onBackPressed() {
        final MTransition transition = MTransitionManager.getInstance().getTransition("example");
        transition.reverse();
    }

一般情况下,在反向动画执行完毕之后,你需要关闭Activity或者做其他操作,这时需要配合监听器Listener去实现:

transition.setOnTransitListener(new TransitListenerAdapter() {
            @Override
            public void onTransitEnd(MTransition transition, boolean reverse) {
               if (reverse) {
                   // reverse为true代表动画是反向的
                   finish();
                   MTranstionUtil.removeActivityAnimation(Example2DetailActivity.this);
               }
            }
        });

跟手动画

1.gif

跟手动画是MTransition与其他过场动画库(尤其是Android自带的Transition)与众不同的地方,是本库的亮点之一;

事实上,跟手动画的核心是MTransition提供了setProgress()接口,可以让你随时让动画播放其中的某一帧,这样你就可以按照自己的喜好,结合TouchEvent事件去实现跟手动画,具体请参考代码库的Demo,如Example10DetailActivity.java;

必须注意一点:由于MTransition动画必须要FromPage和ToPage都存在的情况下才能执行,所以一般情况下,FromPage打开ToPage的过场动画很难用跟手实现(可以实现,只是比较麻烦);ToPage返回FromPage的跟手动画则比较容易;

这里简单说明跟手动画的实现逻辑:
Step1、在跟手动画执行之前,需要调用onBeginDrag():
Step2、根据需要去控制动画执行的进度;
Step3、调用gotoFloor()或者gotoCeil()去完成动画;

@Override
public boolean onTouch(View v, MotionEvent event) {
    boolean result = false;
    int scrolly = scrollView.getScrollY();
    int action = event.getAction();
    if (action == MotionEvent.ACTION_DOWN) {
        mBeginDrag = false;
        mDownY = (int) event.getY();
        mDownScrollY = scrolly;
    } else if (action == MotionEvent.ACTION_MOVE) {
        int delta = (int) (event.getY() - mDownY);
        if (mDownScrollY <= 0 && delta > 20) {
            // 当下拉达到一定阈值,则开始跟手动画
            transition.onBeginDrag();
            mBeginDrag = true;
        }
        if (mBeginDrag) {
            // 根据滑动距离,控制动画的进度
            transition.setProgress(1f - delta / (float) scrollView.getMeasuredHeight());
            result = true;
        }
    } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
        if (mBeginDrag) {
            int delta = (int) (event.getY() - mDownY);
            float progress = 1f - delta / (float) scrollView.getMeasuredHeight();
            // 手指松开时,根据情况让动画走完或者回退
            if (progress < 0.7f) {
                transition.gotoCeil();
            } else {
                transition.gotoFloor();
            }
            result = true;
        }
    }
    return result;
}

自定义动画View,可以结合Lottie或者其他动画库

2.gif
3.gif

MTransition已经提供了一堆基础的动画api,例如平移、旋转、缩放、透明度等。这些api已经可以满足大部分需求,但是如果你需要一些形变或者更加复杂的动画,
你就需要自定义动画。

step1、将你的自定义动画View实现ITransitional接口

step2、调用replaceBy()接口,将你的自定义动画View替换原本的View,让它在过渡动画过程中做动画

该方案可以结合Lottie或者其他动画库,实现一些非常酷炫的效果,如下图,具体请参考本仓库代码中的Demo5、6、7;

有用的Q&A:

Q:为什么我的过场动画背景是白色的?
A:
1、首先请确保设置给FromPage和ToPage的最外层父容器是有背景的,正常情况下,MTransition动画是跟原本View一样的背景;
2、MTransition会默认给FromPage和ToPage的Container设置一层白色背景,防止原View背景是透明的情况,可以参看源代码MTransitionPage.setContainer()的实现。如果你有需要干掉白色背景,你可以自行通过MTransitionPage.getContainer().setBgColor()去修改颜色;

Q:待补充

你可能感兴趣的:(MTransition使用示例、Q&A)