macoal / blog

个人随手
0 stars 0 forks source link

Android Transition #3

Open macoal opened 7 years ago

macoal commented 7 years ago

Transition 主要在三个场景做件事

fade.xml

<?xml version="1.0" encoding="utf-8"?>
<fade xmlns:android="http://schemas.android.com/apk/res/"
    android:duration="1000"/>

slide.xml

<?xml version="1.0" encoding="utf-8"?>
<slide xmlns:android="http://schemas.android.com/apk/res/"
    android:duration="1000"/>

在代码中使用它们

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_transition);
        setupWindowAnimations();
    }
    private void setupWindowAnimations() {
        Slide slide = TransitionInflater.from(this).inflateTransition(R.transition.slide);
//     Fade fade = TransitionInflater.from(this).inflateTransition(R.transition.fade)
//     getWindow().setExitTransition(fade);
        getWindow().setExitTransition(slide);
    }

或者直接在程序中设置它们

    private void setupWindowAnimations() {
        Slide slide = new Slide();
        slide.setDuration(1000);
//     Fade fade = new Fade()
//     fade.setDuration(1000);
//     getWindow().setExitTransition(fade);
        getWindow().setExitTransition(slide);
    }

得到的结果是一样的

每一步的变化

  1. Activity A 启动B
  2. Transition Framework 找到A的ExitTransition()使所有的 views 值为 visible 遵循该方法
  3. Transition Framework 找到B的EnterTransition()并使所有的 views 值为 visible 遵循该方法
  4. 调用backPressed事件,Transition Framework执行enter和exit事件 (如果我们定义了returnTransition 和 reenterTransition,则调用该方法。也就是说,如果我们定义了returnTransition和reenterTransition的话,我们在Activity退出和进入可能会有不同的效果)

    二、Activity共有元素

    有一种设计是在两个不同的布局中有两个不同的 view 但要用一个 Transition 连接它们。Transition Framework 将它认为的,从一个 view 到另一个view 必要的动画展现给用户。但是请谨记:

    view 并不是真的从一个布局移动到另一个布局中。它们是两个完全独立的布局。

    • a) 开启Windows Content Transition

      你需要设置你的 styles.xml

values/styles.xml

<style name="appAnimations" parent="@style/Theme.AppCompat.Light.NoActionBar">
    ...
    <item name="android:windowContentTransitions">true</item
    ...
</style>

你也可以定义你的应用中默认的enter、exit和shared element 转换

<style name="appAnimations" parent="@style/Theme.AppCompat.Light.NoActionBar">
    ...
    <!-- specify enter and exit transitions -->
    <item name="android:windowEnterTransition">@transition/fade</item>
    <item name="android:windowExitTransition">@transition/slide</item>

    <!-- specify shared element transitions -->
    <item name="android:windowSharedElementEnterTransition">@transition/changebounds</item>
    <item name="android:windowSharedElementExitTransition">@transition/changebounds</item>
    ...
</style>

layout/activity_a.xml

<ImageView
        android:id="@+id/small_blue_icon"
        style="@style/MaterialAnimations.Icon.Small"
        android:src="@drawable/circle"
        android:transitionName="@string/blue_name" />

layout/acticity_b.xml

<ImageView
        android:id="@+id/big_blue_icon"
        style="@style/MaterialAnimations.Icon.Big"
        android:src="@drawable/circle"
        android:transitionName="@string/blue_name" />
  • c) 开启一个拥有 shared elsment 的 Activity

    使用 ActivityOptions.makeSceneTransitionAnimation() 方法定义 shared element 起点视图和 Transition 名字。

MainActivity.java

blueIconImageView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent i = new Intent(MainActivity.this, SharedElementActivity.class);
        View sharedView = blueIconImageView;
        String transitionName = getString(R.string.blue_name);
        ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, sharedView, transitionName);
        startActivity(i, transitionActivityOptions.toBundle());
    }
});

Fragment 间的 shared elements

在 Fragment 中使用 shared elements 和在 Activity 中非常相似。a)和b)是一样的,只有c)不一样。

FragmentB fragmentB = FragmentB.newInstance(sample);

// Defines enter transition for all fragment views
Slide slideTransition = new Slide(Gravity.RIGHT);
slideTransition.setDuration(1000);
sharedElementFragment2.setEnterTransition(slideTransition);

// Defines enter transition only for shared element
ChangeBounds changeBoundsTransition = TransitionInflater.from(this).inflateTransition(R.transition.change_bounds);
fragmentB.setSharedElementEnterTransition(changeBoundsTransition);
getFragmentManager().beginTransaction()
        .replace(R.id.content, fragmentB)
        .addSharedElement(blueView, getString(R.string.blue_name))
        .commit();

When true, the enter transition will start as soon as possible.

When false, the enter transition will wait until the exit transition completes before starting.

当是 true 时,enter transition 将会尽可能快速地启动 当是 false 时,enter transition会在exit transition 完成后启动

Shared element transition 在 Fragment 和 Activity 中的都有效

FragmentB fragmentB = FragmentB.newInstance(sample);

// Defines enter transition for all fragment views
Slide slideTransition = new Slide(Gravity.RIGHT);
slideTransition.setDuration(1000);
sharedElementFragment2.setEnterTransition(slideTransition);

// Defines enter transition only for shared element
ChangeBounds changeBoundsTransition = TransitionInflater.from(this).inflateTransition(R.transition.change_bounds);
fragmentB.setSharedElementEnterTransition(changeBoundsTransition);

// Prevent transitions for overlapping
fragmentB.setAllowEnterTransitionOverlap(overlap);
fragmentB.setAllowReturnTransitionOverlap(overlap);

getFragmentManager().beginTransaction()
        .replace(R.id.content, fragmentB)
        .addSharedElement(blueView, getString(R.string.blue_name))
        .commit();

2016年9月3日17:43:13

macoal commented 7 years ago

View 布局变化

Scene 场景

Transition Framework 也可以在当前活动的布局变化中使用动画元素。 Transition 可以发生在 scene 之间。scene 只是一个定义静态UI的常规布局,你可以将一个场景切换到另一个,并且 Transition Framework 将会将两者用动画的形式展现。

scene1 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene1, this);
scene2 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene2, this);
scene3 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene3, this);
scene4 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene4, this);

(...)

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.button1:
            TransitionManager.go(scene1, new ChangeBounds());
            break;
        case R.id.button2:
            TransitionManager.go(scene2, TransitionInflater.from(this).inflateTransition(R.transition.slide_and_changebounds));
            break;
        case R.id.button3:
            TransitionManager.go(scene3, TransitionInflater.from(this).inflateTransition(R.transition.slide_and_changebounds_sequential));
            break;
        case R.id.button4:
            TransitionManager.go(scene4, TransitionInflater.from(this).inflateTransition(R.transition.slide_and_changebounds_sequential_with_interpolators));
            break;  
    }
}

代码会将展现在同一个 Activity 切换四个 scenes ,每个切换都有独特的定义。

Transition Framework 将会得到所有的可见 view 。根据下一场景,计算并显示从当前场景到下一场景过程中任何必要的动画。

布局变化

Transition Framework 也可以用在一个视图的动画属性变化中。你只要确信需要得到任何的改变,它将会为你执行必要的动画。

我们只需要一行代码就可以告诉 Framework 我们要完成一些UI的改变

TransitionManager.beginDelayedTransition(sceneRoot);

改变视图的宽度属性的过程将会触发 layoutMeasure。在这点上, Transition Framework 将会重编码 start 和 ending 值,并且将会创建一个从一个到另一个的切换动画。

Transition 的简单介绍就已经介绍完毕了。

2016年9月4日01:48:20