Android 动画 共享元素 系统学习 完善

之前有写过一个 简陋的  元素共享,  https://blog.csdn.net/FlyPig_Vip/article/details/80961751

现在系统的学习一下关于 这类型的交互

有必要说一下这些 功能Api 都是在Api19 以后才可以使用的

这个有点类似 ConstraintLayout 的 变化前,变化后,MotionLayout 期间加上动画 跟这也差不多

Scene 这个

这是一个场景结合动画 的  中间者

它的实例 有俩种


简单使用

首先写俩个布局

Scene_start1

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">


    <ImageView
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:src="@drawable/ic1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <ImageView
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:src="@drawable/ic2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <ImageView
        android:layout_alignParentLeft="true"
        android:layout_alignParentBottom="true"
        android:src="@drawable/ic3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <ImageView
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"
        android:src="@drawable/ic4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

然后是

Scene_end1

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">


    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:src="@drawable/ic2" />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentRight="true"
        android:src="@drawable/ic1" />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentBottom="true"
        android:src="@drawable/ic4" />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"
        android:src="@drawable/ic3" />
</RelativeLayout>

 主布局:Main1Activity.layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ui.Main1Activity">


    <RelativeLayout
        android:id="@+id/rela1"
        android:layout_width="match_parent"
        android:layout_height="300dp">

    </RelativeLayout>


    <Button
        android:id="@+id/butToggle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="切换场景动画" />
</LinearLayout>

MainAc代码

public class Main1Activity extends AppCompatActivity implements View.OnClickListener {

    private RelativeLayout rela1;
    private Button butToggle;

    private boolean isStartState = true;
    private Scene sceneStart;
    private Scene sceneEnd;

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main1);
        initView();
        initEvent();
        TransitionManager.go(sceneStart);
    }

    /**
     * 设置初始状态
     */
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    private void initEvent() {
        sceneStart = Scene.getSceneForLayout(rela1, R.layout.scene_start1, Main1Activity.this);
        sceneEnd = Scene.getSceneForLayout(rela1, R.layout.scene_end1, Main1Activity.this);
    }

    private void initView() {
        rela1 = (RelativeLayout) findViewById(R.id.rela1);
        butToggle = (Button) findViewById(R.id.butToggle);

        butToggle.setOnClickListener(this);
    }

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.butToggle:
                isStartState = !isStartState;
                TransitionManager.go(isStartState ? sceneStart : sceneEnd);
                break;
            default:
                break;
        }
    }
}

瞬间感觉...原来Android 5.0 的时候就已经出了这些个

这个效果是简单的显隐效果 ,看到这里

TransitionManager.go(isStartState ? sceneStart : sceneEnd);

这个方法有点面熟,像是ConstranitLayout 那个

https://blog.csdn.net/FlyPig_Vip/article/details/99436229

这下加个动画进去

                Transition transition1 = new AutoTransition();
                Transition transition2 = new ChangeBounds();
                Transition transition3 = new Fade();
                Transition transition4 = new ChangeClipBounds();
                Transition transition5 = new ChangeImageTransform();
                Transition transition6 = new ChangeScroll();
                Transition transition7 = new ChangeTransform();
                Transition transition8 = new Explode();
                Transition transition9 = new Slide();
                Transition transition10 = new TransitionSet();

//                TransitionManager.go(isStartState ? sceneStart : sceneEnd, transition1);
//                TransitionManager.go(isStartState ? sceneStart : sceneEnd, transition2);
//                TransitionManager.go(isStartState ? sceneStart : sceneEnd, transition3);
//                TransitionManager.go(isStartState ? sceneStart : sceneEnd, transition4);
//                TransitionManager.go(isStartState ? sceneStart : sceneEnd, transition5);
//                TransitionManager.go(isStartState ? sceneStart : sceneEnd, transition6);
//                TransitionManager.go(isStartState ? sceneStart : sceneEnd, transition7);
//                TransitionManager.go(isStartState ? sceneStart : sceneEnd, transition8);
//                TransitionManager.go(isStartState ? sceneStart : sceneEnd, transition9);

发现我的动画没有人家的 那么精准,于是仔细看了一下,发现我没有给布局字View 加 id,同理 一个图片对应一个id,一定要同步

类似Constraint 的 变化前后的id


效果图:

new Fade()

可以适当的加点View 自带的动画

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">


    <ImageView
        android:alpha="0.8"
        android:id="@+id/iv4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:src="@drawable/ic4" />

    <ImageView
        android:id="@+id/iv3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentRight="true"
        android:src="@drawable/ic3" />

    <ImageView
        android:scaleX="0.5"
        android:scaleY="0.5"
        android:id="@+id/iv2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentBottom="true"
        android:src="@drawable/ic2" />

    <ImageView
        android:rotation="60"
        android:id="@+id/iv1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"
        android:src="@drawable/ic1" />
</RelativeLayout>

 new ChangeBounds()


new ChangeClipBounds()
    View startView = View.inflate(Main1Activity.this, R.layout.scene_start1, null);
        View endView = View.inflate(Main1Activity.this, R.layout.scene_end1, null);

        // 这里的宽高需要事先设置好

        // 可以使用Diputil 转化
//        startView.getWidth();
//        startView.getHeight();


        // 设置裁剪
        startView.setClipBounds(new Rect(0, 0, 200, 200));
        endView.setClipBounds(new Rect(600, 600, 900, 900));


        sceneStart = new Scene(rela1, startView);
        sceneEnd = new Scene(rela1, endView);

只是加了个背景色


new ChangeImageTransform()

总的来说 这个的差距并不大  这个一看就是针对图片的 先把 starView 的 布局 和endView  的 布局  改为一张大图

先是一个AutoTrans   然后是  ChangImageTrans


new Explode()  


 new Slide()


结合使用

我们具体调用这个场景切换动画的时候

                TransitionManager.go(isStartState ? sceneStart : sceneEnd, transition9);

传入的是Transition ,具体看一下他的实例方法

1.

Transition transition1 = new AutoTransition();

2.

                Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.combine_transition);


那么我们自己写一个


TransitionManager.beginDelayedTransition

之前使用的

TransitionManager.go

go需要俩个布局 提前准备好 进行交替 ,beginDelayedTransition 可以直接对布局内View 进行改变


                TransitionManager.beginDelayedTransition(rela1, new AutoTransition());
                if (isStartState) {
                    iv.setScaleX(0.5f);
                    iv.setScaleY(0.5f);
                } else {
                    iv.setScaleX(1.5f);
                    iv.setScaleY(1.5f);
                }


之前也记了 Activity的 跳转动画 现在换一下

https://blog.csdn.net/FlyPig_Vip/article/details/80590316

首先是一个 左进左出的 跳转动画

fade_in

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

    <alpha
        android:fromAlpha="0.6"
        android:toAlpha="1" />
</set>

fade_out

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

    <alpha
        android:fromAlpha="1"
        android:toAlpha="0.6" />
</set>

left_in

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="1000"
        android:fromXDelta="-100%p"
        android:toXDelta="0" />
</set>

left_out

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="1000"
        android:fromXDelta="0"
        android:toXDelta="-100%p" />
</set>

                startActivity(new Intent(Main2Activity.this, Main3Activity.class));
                overridePendingTransition(R.anim.left_in, R.anim.fade_out);
  @Override
    public void onBackPressed() {
        super.onBackPressed();
        overridePendingTransition(R.anim.fade_in, R.anim.left_out);
    }

接下来看一下别的方法

    ActivityOptions compat = ActivityOptions.makeCustomAnimation(Main2Activity.this, R.anim.left_in, R.anim.fade_out);
                startActivity(new Intent(Main2Activity.this, Main3Activity.class), compat.toBundle());

效果是一样的


以布局内某一view 的某一点开始 做放大跳转

                ActivityOptions compat = ActivityOptions.makeScaleUpAnimation(iv, iv.getWidth() / 2, iv.getHeight() / 2, 0, 0);
                startActivity(new Intent(Main2Activity.this, Main3Activity.class), compat.toBundle());

这个看着像是没有作用的 ,也写上吧

  ActivityOptions compat = ActivityOptions.makeThumbnailScaleUpAnimation(iv, BitmapFactory.decodeResource(getResources(),
                        R.mipmap.ic_launcher_round),
                        iv.getWidth() / 2, iv.getHeight() / 2);
                startActivity(new Intent(Main2Activity.this, Main3Activity.class), compat.toBundle());

最后一个是看着可以的 交互了

    ActivityOptions compat = ActivityOptions.makeSceneTransitionAnimation(Main2Activity.this);
                startActivity(new Intent(Main2Activity.this, Main3Activity.class), compat.toBundle());

Main3

public class Main3Activity extends AppCompatActivity {

    private View mViewBackgroundTop;
    private View mViewBackgroundBottom;

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        initTransition();
        setContentView(R.layout.activity_main3);
        mViewBackgroundTop = findViewById(R.id.lltop);
        mViewBackgroundBottom = findViewById(R.id.llbot);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void initTransition() {
        //		//资源文件指定过渡动画
        //		getWindow().setEnterTransition(TransitionInflater.from(this).inflateTransition(R.transition.transition_target));
        //代码制定过渡动画
        final TransitionSet transitionSet = new TransitionSet();
        Slide slide = new Slide(Gravity.BOTTOM);
        slide.addTarget(R.id.shareImage);
        transitionSet.addTransition(slide);


        Explode explode = new Explode();
        explode.excludeTarget(android.R.id.statusBarBackground, true);
        explode.excludeTarget(android.R.id.navigationBarBackground, true);
        explode.excludeTarget(R.id.shareImage, true);
        transitionSet.addTransition(explode);

        //        TransitionSet.ORDERING_SEQUENTIAL
        transitionSet.setOrdering(TransitionSet.ORDERING_SEQUENTIAL);

        getWindow().setEnterTransition(transitionSet);

        transitionSet.addListener(new Transition.TransitionListener() {
            @Override
            public void onTransitionStart(Transition transition) {
                mViewBackgroundTop.setVisibility(View.GONE);
                mViewBackgroundBottom.setVisibility(View.GONE);
            }

            @Override
            public void onTransitionEnd(Transition transition) {
                mViewBackgroundTop.setVisibility(View.VISIBLE);
                mViewBackgroundBottom.setVisibility(View.VISIBLE);
                Animator animationTop = ViewAnimationUtils.createCircularReveal(mViewBackgroundTop, mViewBackgroundTop.getWidth() / 2,
                        mViewBackgroundTop.getHeight() / 2, 0,
                        Math.max(mViewBackgroundTop.getWidth() / 2,
                                mViewBackgroundTop.getHeight() / 2));
                Animator animationBottom = ViewAnimationUtils.createCircularReveal(mViewBackgroundBottom, mViewBackgroundBottom.getWidth(),
                        mViewBackgroundBottom.getHeight(), 0,
                        (float) Math.hypot(mViewBackgroundBottom.getWidth(),
                                mViewBackgroundBottom.getHeight()));

                AnimatorSet animatorSet = new AnimatorSet();
                animatorSet.setDuration(500L);
                animatorSet.playTogether(animationTop, animationBottom);
                animatorSet.start();
                transitionSet.removeListener(this);
            }

            @Override
            public void onTransitionCancel(Transition transition) {

            }

            @Override
            public void onTransitionPause(Transition transition) {

            }

            @Override
            public void onTransitionResume(Transition transition) {

            }
        });
    }
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    tools:context=".ui.Main3Activity">


    <LinearLayout
        android:layout_alignParentTop="true"
        android:background="#f0f"
        android:id="@+id/lltop"
        android:gravity="center_horizontal"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/iv1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic1" />

        <ImageView
            android:id="@+id/iv2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:src="@drawable/ic2" />


    </LinearLayout>

    <ImageView
        android:layout_centerInParent="true"
        android:transitionName="shared_image"
        android:id="@+id/shareImage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic3" />


    <LinearLayout
        android:layout_alignParentBottom="true"
        android:id="@+id/llbot"
        android:background="@drawable/a"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="200dp">


        <ImageView
            android:id="@+id/iv4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:src="@drawable/ic4" />

    </LinearLayout>



</RelativeLayout>

有点突然的就是那个揭露动画了

了解一下

https://blog.csdn.net/FlyPig_Vip/article/details/87798104


元素共享  差不多是 最重要的一环了

Intent intent = new Intent(Main4Activity.this, Main5Activity.class);
                ActivityOptions compat = ActivityOptions.makeSceneTransitionAnimation(Main4Activity.this, shared_image,
                        shared_image.getTransitionName());
                startActivity(intent, compat.toBundle());

监听返回

  setExitSharedElementCallback(new SharedElementCallback() {
            @Override
            public void onSharedElementStart(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {
                super.onSharedElementStart(sharedElementNames, sharedElements, sharedElementSnapshots);
            }

            @Override
            public void onSharedElementEnd(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {
                super.onSharedElementEnd(sharedElementNames, sharedElements, sharedElementSnapshots);
                for (int i = 0; i < sharedElementNames.size(); i++) {
                    System.out.println("sharedElementNames : " + sharedElementNames.get(i));
                }
            }

            @Override
            public void onRejectSharedElements(List<View> rejectedSharedElements) {
                super.onRejectSharedElements(rejectedSharedElements);
            }

            @Override
            public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
                super.onMapSharedElements(names, sharedElements);
            }

            @Override
            public Parcelable onCaptureSharedElementSnapshot(View sharedElement, Matrix viewToGlobalMatrix, RectF screenBounds) {
                return super.onCaptureSharedElementSnapshot(sharedElement, viewToGlobalMatrix, screenBounds);
            }

            @Override
            public View onCreateSnapshotView(Context context, Parcelable snapshot) {
                return super.onCreateSnapshotView(context, snapshot);
            }

            @Override
            public void onSharedElementsArrived(List<String> sharedElementNames, List<View> sharedElements, OnSharedElementsReadyListener listener) {
                super.onSharedElementsArrived(sharedElementNames, sharedElements, listener);
            }
        });

动画进入的监听

private void initShareTransition() {
		//直接在style里面设置了共享元素的Transition
		//		getWindow().setSharedElementEnterTransition(new ChangeBounds());
		//		getWindow().setSharedElementExitTransition(new ChangeBounds());
		//		getWindow().setSharedElementReenterTransition(new ChangeBounds());
		//		getWindow().setSharedElementReturnTransition(new ChangeBounds());


		getWindow().getSharedElementEnterTransition().addListener(new Transition.TransitionListener() {
			@Override
			public void onTransitionStart(Transition transition) {
				mTextInfo.setVisibility(View.GONE);
				mViewBackground.setVisibility(View.GONE);
			}

			@Override
			public void onTransitionEnd(Transition transition) {
				mTextInfo.setVisibility(View.VISIBLE);
				mViewBackground.setVisibility(View.VISIBLE);
				Animator animationBottom = ViewAnimationUtils.createCircularReveal(mTextInfo, mTextInfo.getWidth() / 2,
						mTextInfo.getHeight() / 2, 0,
						(float) Math.max(mTextInfo.getWidth() / 2,
								mTextInfo.getHeight() / 2));

				animationBottom.setDuration(500L);
				animationBottom.start();

				mViewBackground.animate().alpha(1).setDuration(500L).start();

				getWindow().getSharedElementEnterTransition().removeListener(this);
			}

			@Override
			public void onTransitionCancel(Transition transition) {

			}

			@Override
			public void onTransitionPause(Transition transition) {

			}

			@Override
			public void onTransitionResume(Transition transition) {

			}
		});
	}

如果是fragment->fragment

https://www.jianshu.com/p/05e3b99ce5ce

https://www.jianshu.com/p/e87c0086a3ae

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值