利用Transition制作炫酷的切换动画
来源:互联网 发布:移动网络营业 编辑:程序博客网 时间:2024/06/05 04:11
前言
使用Transition动画框架,可以帮你做到:
1不同Activity切换的时候,根据每个activity对应的layout内容的不同做整体的场景变换的动画。
2 不同activity切换的时候,不同activity对应的layout有相同的元素,比如activity1中有一个button,activity2有一个相同的button,transition框架可以在整体场景变换的同时,特别照顾到这个button,让动画变换的过程中,这个button享有视觉连贯性。
3 在相同的activity里,当同一个view内容发生变化,比如在代码中removie或者add了某个ui元素,或者更改了某个已有元素的尺寸,颜色信息,Transition动画框架也可以根据这个变化做动画变换。
一 不同Activity切换的Transition动画
当从activity1跳转到activity2的时候,1会执行exitTransition, 而2会执行enterTransition,你可以在代码中使用
为这个activity设置它进入和退出时需要用到的过场动画(就是方法参数),谷歌为我们预设了几个transition,分别是Explode,Slide,Fade。可以看一下他们的效果getWindow().setExitTransition(slide/fade...);getWindow().setEnterTransition(slide/fade...);
Explode Slide Fade 在定义Explode,Slide,Fade这几个动画效果的时候,可以使用xml也可以直接在代码中定义
1 使用xml
在res/transtion文件夹下定义一个xml文件
res/transition/activity_fade.xml<?xml version="1.0" encoding="utf-8"?><fade xmlns:android="http://schemas.android.com/apk/res/" android:duration="1000"/>res/transition/activity_slide.xml<?xml version="1.0" encoding="utf-8"?><slide xmlns:android="http://schemas.android.com/apk/res/" android:duration="1000"/>然后需要在代码中使用TransitionInflator方法来加载这个xml文件生成对应的动画效果。MainActivity.java @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.activity_slide); getWindow().setExitTransition(slide); }
TransitionActivity.java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_transition); setupWindowAnimations(); } private void setupWindowAnimations() { Fade fade = TransitionInflater.from(this).inflateTransition(R.transition.activity_fade); getWindow().setEnterTransition(fade); }2 在代码中定义
MainActivity.java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_transition); setupWindowAnimations(); } private void setupWindowAnimations() { Slide slide = new Slide(); slide.setDuration(1000); getWindow().setExitTransition(slide); }TransitionActivity.java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_transition); setupWindowAnimations(); } private void setupWindowAnimations() { Fade fade = new Fade(); fade.setDuration(1000); getWindow().setEnterTransition(fade); }效果如下
在这个过程中
首先Actvity1启动了Activity2
Transition框架发现Activity1退出,为activity1里的可见ui组件执行Slide动画
Transition框架发现Activity2退出,为activity2里的可见ui组件执行Fade动画
当按下返回键,如果我们没有为其设置returnTransition和reenterTransition选项的话,Transition框架会对应的activity执行我们为其设置的enter和exit动画运动过程相反的动画作为默认选项。
3 ReturnTransition & ReenterTransition
他们是enterTransition和exitTransition的对应我们把之前那个例子改一下,为TransitionActivity添加一个return动画,用的是Slide,那么当我们按下返回键的时候,会看到一个slide效果,而不是fade(之前设置的enter动画的倒放)效果。TransitionActivity.java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_transition); setupWindowAnimations(); } private void setupWindowAnimations() { Fade fade = new Fade(); fade.setDuration(1000); getWindow().setEnterTransition(fade); Slide slide = new Slide(); slide.setDuration(1000); getWindow().setReturnTransition(slide); }下面可以看到 没有设置return动画和设置了return动画的区别Without Return Transition With Return Transition Enter:Fade In
Enter:Fade In
Exit:Fade Out
Exit:Slide out
二 Activity之间的享元切换
你可以通过为两个不同activity中某个view设置一个唯一的统一的标识,告诉Transition这个view是这两aictivity共享的元素,变换的时候要额外照顾到,那么transition动画框架就会在场景切换的时候,让这个view顺滑的从前一个activity转移到另一个activity(注意,这里的转移并不是真正的转移,这两个item并不是同一个对象,他们是彼此独立的两个view)
1 设置windowContentTransition
首先要对app的style文件做一些修改
values/styles.xml<style name="MaterialAnimations" parent="@style/Theme.AppCompat.Light.NoActionBar"> ... <item name="android:windowContentTransitions">true</item ...</style>
还可以在这里定义整个app默认的 enter, exit 和 shared element transitions动画<style name="MaterialAnimations" parent="@style/Theme.AppCompat.Light.NoActionBar"> ... <!-- specify enter and exit transitions --> <item name="android:windowEnterTransition">@transition/explode</item> <item name="android:windowExitTransition">@transition/explode</item> <!-- specify shared element transitions --> <item name="android:windowSharedElementEnterTransition">@transition/changebounds</item> <item name="android:windowSharedElementExitTransition">@transition/changebounds</item> ...</style>
2在布局文件中为享元view定义相同的Transition Name,通过android:transitioName来定义,享元之间id和属性可以不同,但是TransitionName必须相同。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/activity_b.xml<ImageView android:id="@+id/big_blue_icon" style="@style/MaterialAnimations.Icon.Big" android:src="@drawable/circle" android:transitionName="@string/blue_name" />
c 通过享元方式启动另一个activity通过ActivityOptions.makeSceneTransitionAnimation()方法来定义享元具体是哪个view和Transition Name
MainActivity.javablueIconImageView.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之间进行享元切换动画
前两步和上面基本相同
1 设置windowContentTransition
values/styles.xml<style name="MaterialAnimations" parent="@style/Theme.AppCompat.Light.NoActionBar"> ... <item name="android:windowContentTransitions">true</item> ...</style>2 在布局文件中为享元view定义相同的Transition Namelayout/fragment_a.xml<ImageView android:id="@+id/small_blue_icon" style="@style/MaterialAnimations.Icon.Small" android:src="@drawable/circle" android:transitionName="@string/blue_name" />layout/fragment_b.xml<ImageView android:id="@+id/big_blue_icon" style="@style/MaterialAnimations.Icon.Big" android:src="@drawable/circle" android:transitionName="@string/blue_name" />
3 享元方式启动另一个FragmentFragmentB fragmentB = FragmentB.newInstance(sample);// Defines enter transition for all fragment viewsSlide slideTransition = new Slide(Gravity.RIGHT);slideTransition.setDuration(1000);sharedElementFragment2.setEnterTransition(slideTransition);// Defines enter transition only for shared elementChangeBounds 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();
最终结果如下
四 叠加Transition动画效果
你可以设置是否让exit动画和enter动画叠加在一起执行
如果设置为true 那么enter动画会立刻执行
如果设置为false 那么exter动画会等到exit动画执行完毕之后再执行
这对Fragment和Activity之间的享元切换都有效
FragmentB fragmentB = FragmentB.newInstance(sample);// Defines enter transition for all fragment viewsSlide slideTransition = new Slide(Gravity.RIGHT);slideTransition.setDuration(1000);sharedElementFragment2.setEnterTransition(slideTransition);// Defines enter transition only for shared elementChangeBounds changeBoundsTransition = TransitionInflater.from(this).inflateTransition(R.transition.change_bounds);fragmentB.setSharedElementEnterTransition(changeBoundsTransition);// Prevent transitions for overlappingfragmentB.setAllowEnterTransitionOverlap(overlap);fragmentB.setAllowReturnTransitionOverlap(overlap);getFragmentManager().beginTransaction() .replace(R.id.content, fragmentB) .addSharedElement(blueView, getString(R.string.blue_name)) .commit();
动画是否叠加的具体区别见下面的动图Fragment_2 appears on top of Fragment_1Fragment_2 waits until Fragment_1 is gone 五 在同一个Activity中,根据Activity布局文件中view元素的变动来进行Transition动画
Overlap True Overlap False
1 Scene
在activity对应的布局文件中,定义一个占位用的视图,一般用framelayout,称之为稍后场景变换动画执行
所在的根视图rootView,然后在layout文件夹下,新建几个layout文件,每一个layout文件对应的视图都是一个scene,
可以这么理解,我们打算在Activity对应的界面视图的上半部分放置即将运行的动画,这个上半部分我们用帧布局
占位,称之为rootView,然后动画效果是一个小球从左边移动到右边,那么我们只需要在layout文件夹下面
定义两个layout文件,一个layout文件中,小球在左边,另一个文件中小球在右边。这两个layout,在代码中通过
Scene.getSceneForLayout(rootView,R.layout.***,this)生成一个Scene,此时,rootView和每一个scene的链接关系
就建立起来了。在通过TransitionManager.go方法就可以让动画在rootView中运行起来。
还是看一下代码吧
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);(...)@Overridepublic 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中的四个Scene中间生成对应的动画,而且每个动画都不同
2 布局文件中View属性的变动
Transition动画还可以检测到同一个布局文件中某些视图元素的属性变化,然后做相应的动画效果,你可以随意在代码中修改
你需要的一切变动,比如颜色,大小,位置之类的,之后的动画Transition会自动帮你实现。
做到这些 只需要
a 先调用BeginDelayTransition方法
TransitionManager.beginDelayedTransition(sceneRoot);
b 更改layout布局中的view属性ViewGroup.LayoutParams params = greenIconView.getLayoutParams();params.width = 200;greenIconView.setLayoutParams(params);
更改greenIconView的width时,会触发view的onMeasure()方法,此时Transition框架会记录下该view的起始width值并做出相应的动画
六 享元动画+circle Reveal动画
享元方式的过场动画前面已经提到了,而CircleReveal是属性动画的一种,和享元切换一样都是安卓5.0之后引入的新特性
,对了忘了提,上面享元切换和这个circleReveal动画在执行前最好都加上一个版本判断
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){}
CircleReveal实现圆形缩放效果,可用来突出显示某个部分。他和享元切换一起使用可以引导用户的视觉焦点,给他的点击以反馈。
上面的动画 依次执行了
从MainActivity到RevealActivity的一个享元切换动画
在RevealActivity中有一个监听器,当它监听到RevealActivity中的享元切换动画执行完之后,为Toobar执行了一个CircleReveal属性动画
同时为RevealActivity中其他视图执行了一个放大的属性动画
Listen to shared element enter transition endTransition transition = TransitionInflater.from(this).inflateTransition(R.transition.changebounds_with_arcmotion);getWindow().setSharedElementEnterTransition(transition);transition.addListener(new Transition.TransitionListener() { @Override public void onTransitionEnd(Transition transition) { animateRevealShow(toolbar); animateButtonsIn(); } (...)});Reveal Toolbarprivate void animateRevealShow(View viewRoot) { int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2; int cy = (viewRoot.getTop() + viewRoot.getBottom()) / 2; int finalRadius = Math.max(viewRoot.getWidth(), viewRoot.getHeight()); Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, cx, cy, 0, finalRadius); viewRoot.setVisibility(View.VISIBLE); anim.setDuration(1000); anim.setInterpolator(new AccelerateInterpolator()); anim.start();}Scale up activity layout viewsprivate void animateButtonsIn() { for (int i = 0; i < bgViewGroup.getChildCount(); i++) { View child = bgViewGroup.getChildAt(i); child.animate() .setStartDelay(100 + i * DELAY) .setInterpolator(interpolator) .alpha(1) .scaleX(1) .scaleY(1); }}
更多CircleReveal动画的例子你可以随意设置你想要的Reveal动画,但前提是这些动画可以有效的告知用户 app对用户的点击都做了什么反馈
1 从目标视图中心开始动画
int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2;int cy = viewRoot.getTop();int finalRadius = Math.max(viewRoot.getWidth(), viewRoot.getHeight());Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, cx, cy, 0, finalRadius);viewRoot.setBackgroundColor(color);anim.start();
2 从目标视图顶部开始 并结合其他属性动画int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2;int cy = (viewRoot.getTop() + viewRoot.getBottom()) / 2;int finalRadius = Math.max(viewRoot.getWidth(), viewRoot.getHeight());Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, cx, cy, 0, finalRadius);viewRoot.setBackgroundColor(color);anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { animateButtonsIn(); }});anim.start();3 从点击位置开始动画
@Overridepublic boolean onTouch(View view, MotionEvent motionEvent) { if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { if (view.getId() == R.id.square_yellow) { revealFromCoordinates(motionEvent.getRawX(), motionEvent.getRawY()); } } return false;}private Animator animateRevealColorFromCoordinates(int x, int y) { float finalRadius = (float) Math.hypot(viewRoot.getWidth(), viewRoot.getHeight()); Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, x, y, 0, finalRadius); viewRoot.setBackgroundColor(color); anim.start();}4 结合Transition动画
Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.changebounds_with_arcmotion);transition.addListener(new Transition.TransitionListener() { @Override public void onTransitionEnd(Transition transition) { animateRevealColor(bgViewGroup, R.color.red); } (...)});TransitionManager.beginDelayedTransition(bgViewGroup, transition);RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);btnRed.setLayoutParams(layoutParams);
1 0
- 利用Transition制作炫酷的切换动画
- jQuery Mobile 页面切换动画的使用(data-transition)
- jQuery Mobile 页面切换动画的使用(data-transition)
- 【Transition】Android炫酷的Activity切换效果,共享元素
- 【Transition】Android炫酷的页面切换效果
- CSS3 transition介绍 | 如何设计炫酷的动画效果?
- 利用css3属性:transition-duration来做简单的动画
- Transition(Activity切换过渡动画)
- vue中路由切换动画效果(transition)
- 使用transform和transition制作CSS3动画
- UE4-利用UMG动画制作场景切换Loading进度条
- 利用CSS Transition来实现动画效果
- 简单图片3D变换动画的制作(使用transition、transform)
- Android Transition Framework详解---超炫的动画框架
- Android Transition Framework 详解 --- 超炫的动画框架
- transition动画
- iOS开发中ViewController切换动画的制作
- CSS3--利用transform和transition属性制作扇形导航
- HDU 1043 Eight(A* + 奇偶剪枝 + 康拓展开)
- 基于Http协议的Android网络编程
- RabbitMQ 实现延时队列
- springMVC源码分析--拦截器HandlerExecutionChain(三)
- 关于DialogFragment的一些学习
- 利用Transition制作炫酷的切换动画
- C语言OJ项目参考(2874)包含B的字符串
- POJ 3614 Sunscreen 已被翻译
- spring AOP 零注解配置
- 传统Socket编程的回顾(一)
- POJ 2528 - Mayor's posters(模拟)
- 高质量的java命名规范
- 使用调色板Palette在背景图中取色
- espresso之自由swipe