Android SharedElement详解
2016-04-11 11:16
1006 查看
转至:http://blog.csdn.net/mr_wrong1/article/details/49669275
这个效果目前只支持API21以上,之前的可以使用一些兼容库,比如这个ActivityOptionsICS。废话少说,下面来介绍一下如何去使用和实现这个效果。
想要共享的元素要有相同的
然后就可以去
5.其实现在就已经可以实现简单的共享元素的效果了,就是这么简单。但是上面的效果图可以看到,当切换到其他的图片的时候,依然可以正确的”共享”回来,这就不是简单是设置
开始时从A进入B:
1.A退出(exit) ,A中的View播放动画
2.B进入(enter) ,B中的View播放动画
当从B退回A时:
1.B返回(return) ,B中的View播放动画
2.A重新进入(reenter) ,A中的View播放动画
其实当进入带ActivityB的时候,是应该调用
onMapSharedElements
装载共享元素
onSharedElementStart
是共享元素开始时候回调,一般是进入的时候使用
onSharedElementEnd
是共享元素结束的时候回调,一般是退出的时候使用
当然还有其他的方法,具体可以看看文档。
每次进入和退出都会回调SharedElementCallback,所以一般来说在
当返回到activityA的时候,要去获取activityB返回的信息,可以在
当然,这么说还是很抽象的,有兴趣可以去看一下我的一个开源项目,GitHub地址,欢迎star和提意见。
这里还有一些学习共享元素的开源项目
activity-transitions
MaterialTransitions
Material-Animations
同时也欢迎访问我的个人博客 http://70kg.info
转至:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0201/2394.html
本文将深入分析共享元素变换(shared element transition)以及它在Activity 和Fragment Transitions API中所扮演的角色。这是这Transition系列文章的第三部分:
第一章:
Activity和Fragment Transition介绍
第二章:
深入理解内容变换(Content Transition)
第三章上: 深入理解共享元素变换(Shared Element Transition)
第三章下: Shared Element Transitions In Practice (即将发布)
第四章: Activity & Fragment Transition Examples (即将发布)
第三章(本章)将分为两部分:上着重底层的原理,下着重api的具体实现,比如延迟某些元素变换的重要性以及
进入:
setSharedElementEnterTransition()
设置在B进入时播放的动画,共享元素以A中的位置作为起始,B中的位置为结束来播放动画。
返回:
setSharedElementReturnTransition()
设置在B返回A时的动画,共享元素以B中的位置作为起始,A中的位置为结束来播放动画。
注意,Activity Transition API 也可以使用 setSharedElementExitTransition() 和setSharedElementReenterTransition()方法分别设置共享元素的exit 和reenter 变换。但是一般来讲这是不必要的。如果你想看先关的例子,可以查看这篇博客this blog post.至于为什么Fragment中没有共享元素的exit 和reenter 变换,请查看George Mount在stackoverflow上的回答:this StackOverflow post。
上图演示了google play music应用中的共享元素变换效果。变换包含了两个共享的view元素:一个ImageView以及他的父亲CardView。ImageView在两个activity之间无缝的动画切换,而CardView则是渐渐的扩展到界面上。
在第一章中我们简单的介绍了这个话题,这篇文章则是更深入的去分析共享元素变换(shared element transition)。共享元素变换的原理是什么?有哪些共享元素变换效果可用?共享元素变换动画是如何绘制的,又是在哪里绘制的?接下来的小节中我们将一一回答。
捕获view开始和结束状态以及创建一能在两个状态间渐变的动画。共享元素变换没有什么不同。在共享元素变换开始之前,必须首先捕获每个共享元素的开始和结束状态(调用activity以及被调用activity中的位置、大小、外观),有了这些信息才能决定每个共享元素的入场动画。
和深入理解Content Transition 中类似,framework的共享元素变换是通过运行时改变其属性实现的,当Activity A 调用 Activity B ,发生的事件流如下:
1.Activity A调用startActivity(), Activity B被创建,测量,同时初始化为半透明的窗口和透明的背景颜色。
2.framework重新分配每个共享元素在B中的位置与大小,使其跟A中一模一样。之后,B的进入变换(enter transition)捕获到共享元素在B中的初始状态。
3.framework重新分配每个共享元素在B中的位置与大小,使其跟B中的最终状态一致。之后,B的进入变换(enter transition)捕获到共享元素在B中的结束状态。
4.B的进入变换(enter transition)比较共享元素的初始和结束状态,同时基于前后状态的区别创建一个Animator(属性动画对象)。
5.framework 命令A隐藏其共享元素,动画开始运行。随着动画的进行,framework 逐渐将B的activity窗口显示出来,当动画完成,B的窗口才完全可见。
与内容变换(content transition)取决于view的可见性不同(visibility),共享元素变换取决于每个共享元素的位置、大小以及外观。在api 21中,框架层提供了几个Transition 的实现,可以用于定义共享元素在场景中的切换效果。
ChangeBounds -捕获共享元素的layout bound,然后播放layout bound变化动画。ChangeBounds 是共享元素变换中用的最多的,因为前后两个activity中共享元素的大小和位置一般都是不同的。
ChangeTransform - 捕获共享元素的缩放(scale)与旋转(rotation)属性 ,然后播放缩放(scale)与旋转(rotation)属性变化动画。
ChangeClipBounds - 捕获共享元素clip bounds,然后播放clip bounds变化动画。
ChangeImageTransform - 捕获共享元素(ImageView)的transform matrices 属性,然后播放ImageViewtransform matrices 属性变化动画。与ChangeBounds相结合,这个变换可以让ImageView在动画中高效实现大小,形状或者ImageView.ScaleType 属性平滑过度。
@android:transition/move - 将上述所有变换同时进行的一个TransitionSet 。就如在第一章中所讲的一样,如果共享元素的进入和返回变换没有特别声明,框架将使用它作为默认的变换。
我们可以看到,共享元素变换并不是真正实现了两个activity或者Fragment之间元素的共享,实际上我们看到的几乎所有变换效果中(不管是B进入还是B返回A),共享元素都是在B中绘制出来的。Framework没有真正试图将A中的某个元素传递给B,而是采用了不同的方法来达到相同的视觉效果。A传递给B的是共享元素的状态信息。B利用这些信息来初始化共享View元素,让它们的位置、大小、外观与在A中的时候完全一致。当变换开始的时候,B中除了共享元素之外,所有的其他元素都是不可见的。随着动画的进行,framework 逐渐将B的activity窗口显示出来,当动画完成,B的窗口才完全可见。
虽然不是非常明显的可以看到,共享元素默认其实是绘制在整个view树结构的最上层,在一个叫ViewOverlay的东西上面。你可能没听说过ViewOverlay,他是4.3之后才有的一个新类,它是view的最上面的一个透明的层,添加到ViewOverlay上面的Drawable和view可以被绘制到任何东西的上面,甚至是ViewGroup的子元素。这似乎可以解释为什么framework 会选择ViewOverlay来作为共享元素变换的绘制空间了。
-关于ViewOverlay,除了官方解释还可以看看这篇文章:ViewOverlay与animation介绍
虽然共享元素默认是绘制在ViewOverlay上面,但是framework 还是提供了关闭这个选项的功能,调用Window的setSharedElementsUseOverlay(false) 方法。这样主要是为了防止万一有这样的开发需要。如果你选择了关闭overlay,那么请注意这是有一定副作用的。
在上图的效果中,我们运行了两次不同方式的动画,第二次便是关闭overlay之后的效果,我们可以明显的看到这导致了一个问题。
总之除非有一万个理由,否则不要关闭shared element overlay。
1.元素共享式变换(shared element transition)决定了共享的view元素从一个Activity/Fragment 到另一个Activity/Fragment t的切换中是如何动画变化的。
2.共享元素变换取决于每个共享元素的位置、大小以及外观。
3.共享元素默认其实是绘制在整个view树结构的最上层,在一个叫ViewOverlay的东西上面。
4.共享元素变换并不是真正实现了两个activity或者Fragment之间元素的共享,Framework采用了不同的方法来达到相同的视觉效果。
注:作者在github上上传了一个transaction的demo,虽然没有在文章中明确说明,但我觉得就是这系列文章的相关demo:activity-transitions
本文翻译自
Shared Element Transitions In-Depth (part 3a)
欢迎转载,但请保留本文链接 http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0201/2394.html
概述
SharedElement是什么,翻译是共享元素,但是光说也说不出个杰宝来,no picture say a jb,先看一下效果图,省好多话。这个效果目前只支持API21以上,之前的可以使用一些兼容库,比如这个ActivityOptionsICS。废话少说,下面来介绍一下如何去使用和实现这个效果。
简单原理
俗话说眼见为实,这句话也不一定对,从上面的图可以看到,从activityA的一个图片,变大进入到了activityB里面。好像是把A的图片传递给了B去显示。其实几乎所以的变换都是在B里面完成的,A并没有干什么卵事情。简单的说就是把A里面的图片的位置,大小等信息传递给B,然后B通过这些信息在自己的界面里面绘制出一模一样的,然后在通过比较最终的大小和位置等信息,创建出一个Animator,再然后就是动画的执行。这就看起来像是A里面的元素共享到了B里面。当然具体的过程远比这复杂的多。实现步骤
要使用共享元素,要先在调用和被调用的Activity里面声明,getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);,注意这句话要在
setContentView之前调用。也可以在主题里面声明
<item name="android:windowContentTransitions">true</item>
想要共享的元素要有相同的
TransitionName,可以在XML文件里面声明,或者在代码里面
setTransitionName()。这里使用了
RecyclerView要去设置
TransitionName就应该去
adapter里面设置。这里使用了
AppCompatActivity,所以可以
ViewCompat.setTransitionName(holder.imageView, image.getUrl());,当然也可以
holder.imageView.setTransitionName(image.getUrl());。这个要确保A,B里面要共享的元素拥有相同的
TransitionName,否则
framework将不知道怎么去变换。
然后就可以去
startActivity了,但是这里的
startActivity还需要一个
Bundle对象,用于传递共享元素的一些信息,例如:4.
<code class="hljs avrasm has-numbering">ActivityOptionsCompat options = ActivityOptionsCompat <span class="hljs-preprocessor">.makeSceneTransitionAnimation</span>(this, view, mAdapter<span class="hljs-preprocessor">.get</span>(position)<span class="hljs-preprocessor">.getUrl</span>())<span class="hljs-comment">;</span> startActivity(intent, options<span class="hljs-preprocessor">.toBundle</span>())<span class="hljs-comment">;</span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>
5.其实现在就已经可以实现简单的共享元素的效果了,就是这么简单。但是上面的效果图可以看到,当切换到其他的图片的时候,依然可以正确的”共享”回来,这就不是简单是设置
TransitionName这么简单了。
完善效果
首先要先弄明白两个Activity的转换是分几种情况的:开始时从A进入B:
1.A退出(exit) ,A中的View播放动画
2.B进入(enter) ,B中的View播放动画
当从B退回A时:
1.B返回(return) ,B中的View播放动画
2.A重新进入(reenter) ,A中的View播放动画
其实当进入带ActivityB的时候,是应该调用
setEnterSharedElementCallback(SharedElementCallback),当使用简单的共享元素的时候,可以不写这句话,framwork已经帮我们实现好了。这里写这个是因为有时(滑动页面之后)要返回非进入的共享元素,要去回调过去。当然callback也是可以选择实现方法的,一般没有什么效果的只要实现onMapSharedElements就可以了。再来说一下常用的实现方法:
onMapSharedElements
装载共享元素
onSharedElementStart
是共享元素开始时候回调,一般是进入的时候使用
onSharedElementEnd
是共享元素结束的时候回调,一般是退出的时候使用
当然还有其他的方法,具体可以看看文档。
每次进入和退出都会回调SharedElementCallback,所以一般来说在
onSharedElementStart和
onSharedElementEnd里面要去判断是返回还是进入操作,当进入时,执行
onSharedElementStart,返回时调用
onSharedElementEnd。如何去判断是返回还是进入呢,可以在
finishAfterTransition方法中进行判断,当执行返回操作时,一般是back键时,判断是返回操作,然后去执行
onSharedElementEnd里面的方法,否则去执行
onSharedElementStart里面的方法。同时,要去返回一些共享元素的信息也可以在这里回调回去。比如这里的图片的position。
当返回到activityA的时候,要去获取activityB返回的信息,可以在
onActivityReenter(int requestCode, Intent data)方法里面获取,比如这里获取到返回的position信息,然后去把
RecyclerView滑动到响应的位置。同样的,activityA是要设置
setExitSharedElementCallback的。这样才能响应到返回的共享元素
当然,这么说还是很抽象的,有兴趣可以去看一下我的一个开源项目,GitHub地址,欢迎star和提意见。
这里还有一些学习共享元素的开源项目
activity-transitions
MaterialTransitions
Material-Animations
同时也欢迎访问我的个人博客 http://70kg.info
转至:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0201/2394.html
本文将深入分析共享元素变换(shared element transition)以及它在Activity 和Fragment Transitions API中所扮演的角色。这是这Transition系列文章的第三部分:
第一章:
Activity和Fragment Transition介绍
第二章:
深入理解内容变换(Content Transition)
第三章上: 深入理解共享元素变换(Shared Element Transition)
第三章下: Shared Element Transitions In Practice (即将发布)
第四章: Activity & Fragment Transition Examples (即将发布)
第三章(本章)将分为两部分:上着重底层的原理,下着重api的具体实现,比如延迟某些元素变换的重要性以及
SharedElementCallbacks的实现。
什么是共享元素变换?
元素共享式变换(shared element transition)决定了共享的view元素从一个Activity/Fragment 到另一个Activity/Fragment t的切换中是如何动画变化的。共享元素在被调用Activity进入和返回时播放动画,共享元素在进入和返回时的变换效果通过window和Fragment的如下方法来设置:进入:
setSharedElementEnterTransition()
设置在B进入时播放的动画,共享元素以A中的位置作为起始,B中的位置为结束来播放动画。
返回:
setSharedElementReturnTransition()
设置在B返回A时的动画,共享元素以B中的位置作为起始,A中的位置为结束来播放动画。
注意,Activity Transition API 也可以使用 setSharedElementExitTransition() 和setSharedElementReenterTransition()方法分别设置共享元素的exit 和reenter 变换。但是一般来讲这是不必要的。如果你想看先关的例子,可以查看这篇博客this blog post.至于为什么Fragment中没有共享元素的exit 和reenter 变换,请查看George Mount在stackoverflow上的回答:this StackOverflow post。
上图演示了google play music应用中的共享元素变换效果。变换包含了两个共享的view元素:一个ImageView以及他的父亲CardView。ImageView在两个activity之间无缝的动画切换,而CardView则是渐渐的扩展到界面上。
在第一章中我们简单的介绍了这个话题,这篇文章则是更深入的去分析共享元素变换(shared element transition)。共享元素变换的原理是什么?有哪些共享元素变换效果可用?共享元素变换动画是如何绘制的,又是在哪里绘制的?接下来的小节中我们将一一回答。
共享元素变换揭秘
从前两篇文章中我们知道,一个变换(Transition )主要有两方面的职责:捕获view开始和结束状态以及创建一能在两个状态间渐变的动画。共享元素变换没有什么不同。在共享元素变换开始之前,必须首先捕获每个共享元素的开始和结束状态(调用activity以及被调用activity中的位置、大小、外观),有了这些信息才能决定每个共享元素的入场动画。
和深入理解Content Transition 中类似,framework的共享元素变换是通过运行时改变其属性实现的,当Activity A 调用 Activity B ,发生的事件流如下:
1.Activity A调用startActivity(), Activity B被创建,测量,同时初始化为半透明的窗口和透明的背景颜色。
2.framework重新分配每个共享元素在B中的位置与大小,使其跟A中一模一样。之后,B的进入变换(enter transition)捕获到共享元素在B中的初始状态。
3.framework重新分配每个共享元素在B中的位置与大小,使其跟B中的最终状态一致。之后,B的进入变换(enter transition)捕获到共享元素在B中的结束状态。
4.B的进入变换(enter transition)比较共享元素的初始和结束状态,同时基于前后状态的区别创建一个Animator(属性动画对象)。
5.framework 命令A隐藏其共享元素,动画开始运行。随着动画的进行,framework 逐渐将B的activity窗口显示出来,当动画完成,B的窗口才完全可见。
与内容变换(content transition)取决于view的可见性不同(visibility),共享元素变换取决于每个共享元素的位置、大小以及外观。在api 21中,框架层提供了几个Transition 的实现,可以用于定义共享元素在场景中的切换效果。
ChangeBounds -捕获共享元素的layout bound,然后播放layout bound变化动画。ChangeBounds 是共享元素变换中用的最多的,因为前后两个activity中共享元素的大小和位置一般都是不同的。
ChangeTransform - 捕获共享元素的缩放(scale)与旋转(rotation)属性 ,然后播放缩放(scale)与旋转(rotation)属性变化动画。
ChangeClipBounds - 捕获共享元素clip bounds,然后播放clip bounds变化动画。
ChangeImageTransform - 捕获共享元素(ImageView)的transform matrices 属性,然后播放ImageViewtransform matrices 属性变化动画。与ChangeBounds相结合,这个变换可以让ImageView在动画中高效实现大小,形状或者ImageView.ScaleType 属性平滑过度。
@android:transition/move - 将上述所有变换同时进行的一个TransitionSet 。就如在第一章中所讲的一样,如果共享元素的进入和返回变换没有特别声明,框架将使用它作为默认的变换。
我们可以看到,共享元素变换并不是真正实现了两个activity或者Fragment之间元素的共享,实际上我们看到的几乎所有变换效果中(不管是B进入还是B返回A),共享元素都是在B中绘制出来的。Framework没有真正试图将A中的某个元素传递给B,而是采用了不同的方法来达到相同的视觉效果。A传递给B的是共享元素的状态信息。B利用这些信息来初始化共享View元素,让它们的位置、大小、外观与在A中的时候完全一致。当变换开始的时候,B中除了共享元素之外,所有的其他元素都是不可见的。随着动画的进行,framework 逐渐将B的activity窗口显示出来,当动画完成,B的窗口才完全可见。
使用共享元素的 Overlay
最后,我们需要讨论一下shared element overlay这个概念才算是对共享元素变换的绘制过程有了一个完整的了解。虽然不是非常明显的可以看到,共享元素默认其实是绘制在整个view树结构的最上层,在一个叫ViewOverlay的东西上面。你可能没听说过ViewOverlay,他是4.3之后才有的一个新类,它是view的最上面的一个透明的层,添加到ViewOverlay上面的Drawable和view可以被绘制到任何东西的上面,甚至是ViewGroup的子元素。这似乎可以解释为什么framework 会选择ViewOverlay来作为共享元素变换的绘制空间了。
-关于ViewOverlay,除了官方解释还可以看看这篇文章:ViewOverlay与animation介绍
虽然共享元素默认是绘制在ViewOverlay上面,但是framework 还是提供了关闭这个选项的功能,调用Window的setSharedElementsUseOverlay(false) 方法。这样主要是为了防止万一有这样的开发需要。如果你选择了关闭overlay,那么请注意这是有一定副作用的。
在上图的效果中,我们运行了两次不同方式的动画,第二次便是关闭overlay之后的效果,我们可以明显的看到这导致了一个问题。
总之除非有一万个理由,否则不要关闭shared element overlay。
总结
这篇文章涵盖了如下几个要点:1.元素共享式变换(shared element transition)决定了共享的view元素从一个Activity/Fragment 到另一个Activity/Fragment t的切换中是如何动画变化的。
2.共享元素变换取决于每个共享元素的位置、大小以及外观。
3.共享元素默认其实是绘制在整个view树结构的最上层,在一个叫ViewOverlay的东西上面。
4.共享元素变换并不是真正实现了两个activity或者Fragment之间元素的共享,Framework采用了不同的方法来达到相同的视觉效果。
注:作者在github上上传了一个transaction的demo,虽然没有在文章中明确说明,但我觉得就是这系列文章的相关demo:activity-transitions
本文翻译自
Shared Element Transitions In-Depth (part 3a)
欢迎转载,但请保留本文链接 http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0201/2394.html
相关文章推荐
- Android 文件操作心得体会
- Android复习之AndroidMainfest属性详解
- 【Launcher3】默认壁纸的设置
- 深入浅析Android手机卫士保存密码时进行md5加密
- 如何让Listview的item有不同样子
- Handler:Android异步消息处理机制完全解析
- Android Studio导入 setting.jar 后报错 解决方案
- android onTouchEvent和setOnTouchListener中onTouch的区别
- android平台获取手机IMSI,IMEI ,序列号,和 手机号的方法
- 详解Android 手机卫士设置向导页面
- 这些小工具让你的Android 开发更高效
- 安卓设置背景色的透明度
- 初次使用Android Studio时的配置
- Android中内容观察者的使用---- ContentObserver类详解
- Android应用方法数65536的限制问题
- Android Studio设置,鼠标放上去有提示
- Android程序的反破解技术
- Android-布局的优化及其使用
- 详解Android Activity之间切换传递数据的方法
- android studio 获取证书指纹 SHA1