网络科技

    今日:1177| 主题:245562
收藏本版
互联网、科技极客的综合动态。

[其他] Android 中的转场动画及兼容处理

[复制链接]
大病猫c 发表于 2016-10-17 03:07:28
160 17

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
Android 中的动画有很多,除了在一个界面上使用帧动画、属性动画将一个或多个 View 进行动画处理以外,还可以用于两个界面之间过渡、跳转。在 Android 5.0 之前,我们已经有了 overridePendingTransition() 方法来实现一些转场效果。然而,在 Android 5.0 以后,转场效果更加炫酷。 比如下面的动画:
   
Android 中的转场动画及兼容处理-1 (transition,Android,android,文件夹,style)

  本篇文章,主要就是解说如何实现上述的效果。主要内容包括:
  
       
  • Android 5.0+ 的转场动画   
  • Android 4.X 模拟实现 Android 5.0+ 转场效果。  
  Android L 中的转场动画

  实现转场动画只需三步:
  
       
  • res/ 目录下创建 transition 文件夹,在该文件夹下定义界面转场动画和共享元素的动画。   
  • res/value/style 文件中为每个 Activity 指定转场动画的 style ,并在 AndroidManifest.xml 文件中为每个 Activity 设置对应的 android:theme 。   
  • 在 Activity 调用 startActivity() 切换动画前,使用 ActivityOptionsCompat 来创建转场动画时的共享对象。  
  下面就来对这三步进行详细讲解。
  定义转场动画

   在 res/ 目录下创建了 transition 资源文件夹后,就可以在该文件夹下对每一种动画进行定义。
  一般来说,对 Activity 定义一个过渡动画可以写成下面的形式:
         [code]                  [/code]        其中,  是动画效果的名称,Android 5.0(API 级别 21)支持这些进入与退出转换:
  
       
  • 分解(explode) :从场景中心移入或移出视图。   
  • 滑动(slide) :从场景边缘移入或移出视图。   
  • 淡入淡出(fade) :通过调整透明度在场景中增添或移除视图。  
   而每一种动画效果,都有额外的属性。比如滑动 slide,可以使用 android:slideEdge="top" 设置滑动的方向;淡入淡出(fade)可以使用 android:fadingMode="fade_in" 设置具体是淡入(fade_in)还是淡出(fade_out)等。
   标签里面定义需要转场(或者不需要转场)的目标 id ,这个 id 可以使系统自带的,也可以是我们自己视图中的 view 的 id,每一个 id 需要单独在       标签中定义,    android:targetId 表示目标ID需要进行过渡转换的 view,而    android:excludeId 表示我们不需要该 ID 的 view 进行过渡转场。上面的那段代码的意思是说,除了状态栏和导航栏以外所有的 view,都执行 explode 动画。   
   如果我们想要在同一个过渡状态中实现两种或多种动画效果怎么办?也简单,将根标签替换为  ,然后定义每一种动画效果,最后记得在根标签中使用 android:transitionOrdering 注明这几种动画的演示顺序, sequential 表示顺序执行,而 together 表示同时执行。比如像下面的代码:
         [code]                                                                                                [/code]       这段代码的意思就很简单了,该 xml 定义了两个过渡动画,并且同时执行。第一个动画是针对 id 为 cardView 的 view 进行滑动,第二个动画将除了状态栏、导航栏和 cardview 以外的 view,进行淡入淡出。
  为每个 Activity 定义转场样式

   这里的 每一种 动画,指的是在进行界面跳转过渡时,两个界面的状态。比如对于 Activity A 和 Activity B 这两个界面,可能的状态如下:
  
       
  • 界面 A 跳转至界面 B :这时界面 A 是 退出(exit ) 过渡状态,而对应的界面B是 进入(enter) 过渡状态。   
  • 界面 B 返回到界面 A :这时界面 A 是 重新进入(reenter) 过渡,而对应的界面B则是 返回(return) 过渡。  
  一般来说,所有的 Activity 过渡动画都可以定义成如下的形式:
         [code][/code]       当然,你可以不用写全,比如在我的 Demo 中一个界面的转场动画文件如下:
         [code][/code]       调用 ActivityOptionsCompat

   转场动画是在两个界面的跳转返回时发生的,所以,当使用 intent 跳转界面时,需要调用 ActivityOptionsCompat 来指定动画的运行。
   一般来说,调用 ActivityOptionsCompat 的模板代码如下:
         [code]// 创建一个包含过渡动画信息的 ActivityOptions 对象ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, view, getString(R.string.image_transition_name));// 使用 Intent 跳转界面,并传递共享对象信息Intent intent = new Intent(this, DetailActivity.class);startActivity(intent, optionsCompat.toBundle());[/code]       ActivityOptionsCompat 是在support v4 包里面的,其实它是 ActivityOptions 的一个兼容(ActivityOptions是API 16引入的)。
  然后,我们需要在第二个 Activity 中,将转场的图片获取并显示到界面中。
  多个共享元素的过渡实现

  有时候我们需要让多个元素产生动画效果,可以使用 Pair<> 来实现:
         [code]ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, Pair.create(view1, "agreedName1"), Pair.create(view2, "agreedName2"));[/code]       手动实现一个转场动画

  现在市面上,Android 5.0 以下的手机系统还有一定的市场份额,所以为了照顾这些用户,我们只能手动实现一下共享元素的转场动画效果。
  实现的思路也比较简单,大概的步骤如下:
  
       
  • 确定第一个界面的共享元素,将其信息传递个第二个界面   
  • 第二个界面接收信息,开始的时候将界面设置为透明,并只显示共享元素。   
  • 将第二个界面的共享元素进行动画处理。  
  那么我们开始一步步实现上面的步骤。
  获取共享元素位置信息

  在第一个界面中,我们需要获取到共享元素的位置信息,并将其传递给下一个界面。于是乎,我们可以在第一个界面元素点击事件中,这么写:
         [code]public void imageClick(View view) {    Intent intent = new Intent(AnimeActivity.this, AnimeDetailActivity.class);    // 创建一个 rect 对象来存储共享元素位置信息    Rect rect = new Rect();    // 获取元素位置信息    view.getGlobalVisibleRect(rect);    // 将位置信息附加到 intent 上    intent.setSourceBounds(rect);    CustomImage customImage = (CustomImage) view;    intent.putExtra(AnimeDetailActivity.EXTRA_IMAGE, customImage.getImageId());    startActivity(intent);    // 屏蔽 Activity 默认转场效果    overridePendingTransition(0, 0);}[/code]        其中, getGlobalVisibleRect() 方法的含义是,获取 可见的状态栏高度+可见的标题栏高度+Rect左上角到标题栏底部的距离 ,如果标题栏被隐藏了,那么 可见标题栏高度 为0。
  接下来,就在在第二个界面接收位置信息并将该图片展示出来了。
  模拟转场动画

  在第二个界面中,我们需要做如下的操作:
  
       
  • 获取上共享元素信息。   
  • 计算共享元素缩放比例和位移距离。   
  • 调用动画,完成模拟转场效果。  
   我将上面三个步骤的代码如下,你也可以下载我完整的 Demo 来查看。
         [code]private void initial() {    // 获取上一个界面传入的信息    mRect = getIntent().getSourceBounds();    mRescourceId = getIntent().getExtras().getInt(EXTRA_IMAGE);    // 获取上一个界面中,图片的宽度和高度    mOriginWidth = mRect.right - mRect.left;    mOriginHeight = mRect.bottom - mRect.top;    // 设置 ImageView 的位置,使其和上一个界面中图片的位置重合    FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(mOriginWidth, mOriginHeight);    params.setMargins(mRect.left, mRect.top - getStatusBarHeight(), mRect.right, mRect.bottom);    mImageView.setLayoutParams(params);    // 设置 ImageView 的图片和缩放类型    mImageView.setImageResource(mRescourceId);    mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);    // 根据上一个界面传入的图片资源 ID,获取图片的 Bitmap 对象。    BitmapDrawable bitmapDrawable = (BitmapDrawable) getResources().getDrawable(mRescourceId);    Bitmap bitmap = bitmapDrawable.getBitmap();    // 计算图片缩放比例和位移距离    getBundleInfo(bitmap);    // 创建一个 Pallette 对象    mImagePalette = Palette.from(bitmap).generate();    // 使用 Palette 设置背景颜色    mContainer.setBackgroundColor(            mImagePalette.getVibrantColor(ContextCompat.getColor(this, android.R.color.black)));}[/code]       在12行,通过设置 Margin 的形式来确定图片的位置,需要注意的是,由于状态栏是在父控件 FramLayout 之外的,因此我们要将 Rect.top 的值减去状态栏的高度,这样才是相对于屏幕的绝对位置。然后,getBundleInfo() 方法的代码如下:
         [code]private void getBundleInfo(Bitmap bitmap) {    // 计算图片缩放比例,并存储在 bundle 中    if (bitmap.getWidth() >= bitmap.getHeight()) {        mScaleBundle.putFloat(SCALE_WIDTH, (float) mScreenWidth / mOriginWidth);        mScaleBundle.putFloat(SCALE_HEIGHT, (float) bitmap.getHeight() / mOriginHeight);    } else {        mScaleBundle.putFloat(SCALE_WIDTH, (float) bitmap.getWidth() / mOriginWidth);        mScaleBundle.putFloat(SCALE_HEIGHT, (float) mScreenHeight / mOriginHeight);    }    // 计算位移距离,并将数据存储到 bundle 中    mTransitionBundle.putFloat(TRANSITION_X, mScreenWidth / 2 - (mRect.left + (mRect.right - mRect.left) / 2));    mTransitionBundle.putFloat(TRANSITION_Y, mScreenHeight / 2 - (mRect.top + (mRect.bottom - mRect.top) / 2));}[/code]       动画处理

  最后我们需要使用动画来模拟转场效果,代码如下:
         [code]private void runEnterAnim() {    mImageView.animate()              .setInterpolator(DEFAULT_INTERPOLATOR)              .setDuration(DURATION)              .scaleX(mScaleBundle.getFloat(SCALE_WIDTH))              .scaleY(mScaleBundle.getFloat(SCALE_HEIGHT))              .translationX(mTransitionBundle.getFloat(TRANSITION_X))              .translationY(mTransitionBundle.getFloat(TRANSITION_Y))              .start();}[/code]       很简单,自此,入场动画效果基本模拟完毕。
  而退场动画就更简单了,直接上代码:
         [code]                                                                                                0[/code]       所以,是不是很简单?
   本篇文章的 Demo 地址: UITransitionDemo
   推荐阅读: 定义定制动画
友荐云推荐




上一篇:JavaScript函数式真正的浅析
下一篇:彭蕾:蚂蚁金服仍是创业公司 创新是最重要DNA
酷辣虫提示酷辣虫禁止发表任何与中华人民共和国法律有抵触的内容!所有内容由用户发布,并不代表酷辣虫的观点,酷辣虫无法对用户发布内容真实性提供任何的保证,请自行验证并承担风险与后果。如您有版权、违规等问题,请通过"联系我们"或"违规举报"告知我们处理。

物是人非〃 发表于 2016-10-17 08:10:14
这次必须是沙发!
回复 支持 反对

使用道具 举报

kxwh9bRy 发表于 2016-10-17 08:24:19
路过 帮顶 嘿嘿
回复 支持 反对

使用道具 举报

vtizdmkw 发表于 2016-10-17 08:24:22
为了三千积分!
回复 支持 反对

使用道具 举报

廖翠 发表于 2016-10-17 08:24:25
我死了,但是在烈火中我又站起来了,你猜是涅磐,还是尸变?
回复 支持 反对

使用道具 举报

炒货i 发表于 2016-10-17 08:24:28
顶起来・・・・・・
回复 支持 反对

使用道具 举报

pcy5gw 发表于 2016-10-17 08:24:34
楼猪V5啊
回复 支持 反对

使用道具 举报

怪獸般的清操 发表于 2016-10-17 09:30:38
永远不要给背叛过自己的朋友第二次背叛的机会。
回复 支持 反对

使用道具 举报

士官长 发表于 2016-10-17 09:34:42
在撸一遍。。。
回复 支持 反对

使用道具 举报

点赞 发表于 2016-10-17 15:17:30
回帖淹没我们,潜水拆散我们
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表手机版
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )|网站地图 酷辣虫

© 2001-2016 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表