|
|
|
|
公众号矩阵

Android转场动画深度解析

Activity的转场动画很早就有了,5.0之前用的是overridePendingTransition()这个方法。在5.0之后,Google使用Material Design设计风格,进而有了的新的转场转场动画的诞生,效果还是挺炫酷的。

作者:Android开发编程来源:Android开发编程|2021-10-12 11:07

前言

所谓转场动画,通俗的讲就是一个Activity跳转到另一个Activity是的动画;Activity的转场动画很早就有了,5.0之前用的是overridePendingTransition()这个方法。在5.0之后,Google使用Material Design设计风格,进而有了的新的转场转场动画的诞生,效果还是挺炫酷的;今天我们就来讲解下。

一、转场动画兼容性

1、API21之前Activity过渡动画使用

API21之前Activity过渡动画通过两种方式来实现:style主题里面统一设置、使用代码overridePendingTransition函数单独设置;

style文件主题里面统一定义,全局为所有Activity设置过渡动画效果;

  1. <item name="android:windowAnimationStyle">@style/Animation.Activity.Customer</item> 
  2.     <style name="Animation.Activity.Customer" parent="@android:style/Animation.Activity"
  3.         <!-- 进入一个新的Activity的时候,A->B B进入动画 --> 
  4.         <item name="android:activityOpenEnterAnimation">@anim/right_in</item> 
  5.         <!-- 进入一个新的Activity的时候,A->B A退出动画 --> 
  6.         <item name="android:activityOpenExitAnimation">@anim/left_out</item> 
  7.         <!-- 退出一个Activity的时候,B返回到A A进入动画 --> 
  8.         <item name="android:activityCloseEnterAnimation">@anim/left_in</item> 
  9.         <!-- 退出一个Activity的时候,B返回到A B退出动画 --> 
  10.         <item name="android:activityCloseExitAnimation">@anim/right_out</item> 
  11. </style> 

代码overridePendingTransition(enterAnim, exitAnim);

关于overridePendingTransition函数,有一个需要注意的地方就是:它必需紧挨着startActivity()或者finish()或者onBackPressed()函数调用,否则不一定有效果;

2、API 21 之后Activity过渡动画使用

在API 21之后google又推出了一种比之前效果更加赞的过渡动画;

通过ActivityOptions + Transition来实现Activity过渡动画;

所以在使用之前需要进行版本判断。当版本API 大于21时使用转场动画,否则不使用;

  1. // Check if we're running on Android 5.0 or higher 
  2. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
  3.     // Apply activity transition 
  4. else { 
  5.     // Swap without transition 

ActivityOptions + Transition来实现Activity过渡动画之前先来了看下ActivityOptions里面几个函数代表啥意思;

  1. /** 
  2.  * 和overridePendingTransition类似,设置跳转时候的进入动画和退出动画 
  3.  */ 
  4. public static ActivityOptions makeCustomAnimation(Context context, int enterResId, int exitResId); 
  5. /** 
  6.  * 通过把要进入的Activity通过放大的效果过渡进去 
  7.  * 举一个简单的例子来理解source=view,startX=view.getWidth(),startY=view.getHeight(),startWidth=0,startHeight=0 
  8.  * 表明新的Activity从view的中心从无到有慢慢放大的过程 
  9.  */ 
  10. public static ActivityOptions makeScaleUpAnimation(View source, int startX, int startY, int width, int height); 
  11. /** 
  12.  * 通过放大一个图片过渡到新的Activity 
  13.  */ 
  14. public static ActivityOptions makeThumbnailScaleUpAnimation(View source, Bitmap thumbnail, int startX, int startY); 
  15. /** 
  16.  * 场景动画,体现在两个Activity中的某些view协同去完成过渡动画效果,等下在例子中能更好的看到效果 
  17.  */ 
  18. public static ActivityOptions makeSceneTransitionAnimation(Activity activity, View sharedElement, String sharedElementName); 
  19. /** 
  20.  * 场景动画,同上是对多个View同时起作用 
  21.  */ 
  22. public static ActivityOptions makeSceneTransitionAnimation(Activity activity, android.util.Pair<View, String>... sharedElements); 

对于Transition Activity过渡动画的使用,我们简单的分为三个步骤:告诉系统以Transition的方式启动Activity、定义过渡动画、设置过渡动画。

3、转场动画的使用场景

Android中的转场动画主要有三种场景:

  • 在两个activity之间切换时界面的过渡效果;
  • 两个activity或者Fragment之间shared elements 切换效果;

下面分别详细的介绍。

二、转场动画的使用场景

1、两个activity之间切换时界面的过渡效果

两个activity切换时的,有两个动画,从activity A 切换到activity B时,会有A的退出动画和B的进入动画;

在Google提供的android.transition.Transition包中从activity A切换到activity B有三种方式:Explode, Slide 和Fade;

  • Explode:从屏幕的中间进入或退出;
  • Slide:从屏幕的一边向另一边进入或退出;
  • Fade:通过改变透明度来出现或消失;

上面的三种动画有两种实现方式:

①通过xml声明;

在res目录下新建transition文件夹在transition文件夹下新建activity_fade.xml文件;

activity_fade.xml

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

activity_slide.xml

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

ActivityA的代码如下:因为从ActivityA切换到ActivityB,所以ActivityA是退出动画使用的方法是:getWindow().setExitTransition(slide);

  1. @Override 
  2.     protected void onCreate(Bundle savedInstanceState) { 
  3.         super.onCreate(savedInstanceState); 
  4.         setContentView(R.layout.activity_transition); 
  5.         setupWindowAnimations(); 
  6.     } 
  7.     private void setupWindowAnimations() { 
  8.         Slide slide = TransitionInflater.from(this).inflateTransition(R.transition.activity_slide); 
  9.         getWindow().setExitTransition(slide); 
  10.     } 

ActivityB是进入动画使用方法:getWindow().setEnterTransition(fade);,ActivityB的代码如下

  1. @Override 
  2.     protected void onCreate(Bundle savedInstanceState) { 
  3.         super.onCreate(savedInstanceState); 
  4.         setContentView(R.layout.activity_transition); 
  5.         setupWindowAnimations(); 
  6.     } 
  7.     private void setupWindowAnimations() { 
  8.         Fade fade = TransitionInflater.from(this).inflateTransition(R.transition.activity_fade); 
  9.         getWindow().setEnterTransition(fade); 
  10.     } 

②代码方式

ActivityA代码如下:实现一个Slide对象并且设置时间为1000毫秒

  1. @Override 
  2.     protected void onCreate(Bundle savedInstanceState) { 
  3.         super.onCreate(savedInstanceState); 
  4.         setContentView(R.layout.activity_transition); 
  5.         setupWindowAnimations(); 
  6.     } 
  7.     private void setupWindowAnimations() { 
  8.         Slide slide = new Slide(); 
  9.         slide.setDuration(1000); 
  10.         getWindow().setExitTransition(slide); 
  11.     } 

ActivityB中实现一个Fide对象并且设置时间为1000毫秒;

  1. @Override 
  2.     protected void onCreate(Bundle savedInstanceState) { 
  3.         super.onCreate(savedInstanceState); 
  4.         setContentView(R.layout.activity_transition); 
  5.         setupWindowAnimations(); 
  6.     } 
  7.     private void setupWindowAnimations() { 
  8.         Fade fade = new Fade(); 
  9.         fade.setDuration(1000); 
  10.         getWindow().setEnterTransition(fade); 
  11.     } 

2、两个activity或者Fragment之间shared elements 切换效果

Shared elements转换确定两个Activity之间共享的视图如何在这两个Activity之间转换;

如果两个Activity在不同的位置和大小中具有相同的图像,则通过Shared elements转换会在这两个Activity之间平滑地转换和缩放图像;

当从Activity A跳转到Activity B时,ActivityA, ActivityB中的两个item有动画变化,但是要注意的时ActivityA ,ActivityB中的item是两个独立的item;

shared elements转换包括以下几种:

  • changeBounds 改变目标布局中view的边界
  • changeClipBounds 裁剪目标布局中view的边界
  • changeTransform 实现旋转或者缩放动画
  • changeImageTransform 实现目标布局中ImageView的旋转或者缩放动画

实现上面的效果需要三个步骤:

① Window Content Transition

设置styles.xml文件,允许windowContentTransitions如下:

  1. value/style.xml 
  2. <style name="MaterialAnimations" parent="@style/Theme.AppCompat.Light.NoActionBar"
  3.     ... 
  4.     <item name="android:windowContentTransitions">true</item 
  5.     ... 
  6. </style> 

②定义一个相同的transition名称

分别在Activity A 和Activity B的布局文件中定义item,这两个item的属性可以不一样,但是android:transitionName必须一样。如下:

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

activity_b.xml

  1. <ImageView 
  2.         android:id="@+id/big_blue_icon" 
  3.         style="@style/MaterialAnimations.Icon.Big" 
  4.         android:src="@drawable/circle" 
  5.         android:transitionName="@string/blue_name" /> 

③在activity中启动shared element

使用ActivityOptions.makeSceneTransitionAnimation()方法

ActivityA.java

  1. blueIconImageView.setOnClickListener(new View.OnClickListener() { 
  2.     @Override 
  3.     public void onClick(View v) { 
  4.         Intent i = new Intent(MainActivity.this, SharedElementActivity.class); 
  5.         View sharedView = blueIconImageView; 
  6.         String transitionName = getString(R.string.blue_name); 
  7.         ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, sharedView, transitionName); 
  8.         startActivity(i, transitionActivityOptions.toBundle()); 
  9.     } 
  10. }); 

Fragment之间Shared elements

Fragment之间的Shared elements的使用过程和Activity之间的类似,分为三个步骤:

①允许windowContentTransitions

  1. <style name="MaterialAnimations" parent="@style/Theme.AppCompat.Light.NoActionBar"
  2.     ... 
  3.     <item name="android:windowContentTransitions">true</item> 
  4.     ... 
  5. </style> 

②定义一个共同的变换名称

layout/fragment_a.xml

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

layout/fragment_b.xml

  1. <ImageView 
  2.         android:id="@+id/big_blue_icon" 
  3.         style="@style/MaterialAnimations.Icon.Big" 
  4.         android:src="@drawable/circle" 
  5.         android:transitionName="@string/blue_name" /> 

③使用FragmentTransaction

  1. FragmentB fragmentB = FragmentB.newInstance(sample); 
  2. // Defines enter transition for all fragment views 
  3. Slide slideTransition = new Slide(Gravity.RIGHT); 
  4. slideTransition.setDuration(1000); 
  5. sharedElementFragment2.setEnterTransition(slideTransition); 
  6. // Defines enter transition only for shared element 
  7. ChangeBounds changeBoundsTransition = TransitionInflater.from(this).inflateTransition(R.transition.change_bounds); 
  8. fragmentB.setSharedElementEnterTransition(changeBoundsTransition); 
  9. getFragmentManager().beginTransaction() 
  10.         .replace(R.id.content, fragmentB) 
  11.         .addSharedElement(blueView, getString(R.string.blue_name)) 
  12.         .commit(); 

【编辑推荐】

  1. 深度学习项目实战视频课程-StyleTransfer(基于Tensorflow)
  2. Android进阶之Coil-为kotlin而生的图片库详解
  3. 浅析Android Root,你懂了吗?
  4. Android版Chrome浏览器将新增页面缩放功能
  5. 自监督深度估计算法,比肩有监督,泛化性能更佳
【责任编辑:武晓燕 TEL:(010)68476606】

点赞 0
分享:
大家都在看
猜你喜欢

订阅专栏+更多

带你轻松入门 RabbitMQ

带你轻松入门 RabbitMQ

轻松入门RabbitMQ
共4章 | loong576

50人订阅学习

数据湖与数据仓库的分析实践攻略

数据湖与数据仓库的分析实践攻略

助力现代化数据管理:数据湖与数据仓库的分析实践攻略
共3章 | 创世达人

14人订阅学习

云原生架构实践

云原生架构实践

新技术引领移动互联网进入急速赛道
共3章 | KaliArch

42人订阅学习

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊

51CTO服务号

51CTO官微