热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android中转场动画的实现与兼容性处理

大家都知道Android中的动画有很多,除了在一个界面上使用帧动画、属性动画将一个或多个View进行动画处理以外,还可以用于两个界面之间过渡、跳转。本文的内容包括:Android5.0+的转场动画和Android4.X模拟实现Android5.0+转场效果。有需要的可以参考借鉴。

前言

在 Android 5.0 之前,我们已经有了 overridePendingTransition() 方法来实现一些转场效果。然而,在 Android 5.0 以后,转场效果更加炫酷。

比如下面的动画:

一、Android L 中的转场动画

实现转场动画只需三步:

       在 res/ 目录下创建 transition 文件夹,在该文件夹下定义界面转场动画和共享元素的动画。

       在 res/value/style 文件中为每个 Activity 指定转场动画的 style ,并在 AndroidManifest.xml 文件中为每个 Activity 设置对应的 android:theme。

       在 Activity 调用 startActivity() 切换动画前,使用 ActivityOptionsCompat 来创建转场动画时的共享对象。
下面就来对这三步进行详细讲解。

二、定义转场动画

在 res/ 目录下创建了 transition 资源文件夹后,就可以在该文件夹下对每一种动画进行定义。

一般来说,对 Activity 定义一个过渡动画可以写成下面的形式:


 
  
  
 

其中, 是动画效果的名称,Android 5.0(API 级别 21)支持这些进入与退出转换:

       1、分解(explode):从场景中心移入或移出视图。

       2、滑动(slide):从场景边缘移入或移出视图。

       3、淡入淡出(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 表示同时执行。

比如像下面的代码:


 
  
   
  
 

 
  
   
   
   
  
 

这段代码的意思就很简单了,该 xml 定义了两个过渡动画,并且同时执行。第一个动画是针对 id 为 cardView 的 view 进行滑动,第二个动画将除了状态栏、导航栏和 cardview 以外的 view,进行淡入淡出。

三、为每个 Activity 定义转场样式

这里的每一种动画,指的是在进行界面跳转过渡时,两个界面的状态。比如对于 Activity A 和 Activity B 这两个界面,可能的状态如下:

       1、界面 A 跳转至界面 B :这时界面 A 是退出(exit )过渡状态,而对应的界面B是进入(enter)过渡状态。

       2、界面 B 返回到界面 A :这时界面 A 是重新进入(reenter)过渡,而对应的界面B则是返回(return)过渡。

一般来说,所有的 Activity 过渡动画都可以定义成如下的形式:


当然,你可以不用写全,比如在我的 Demo 中一个界面的转场动画文件如下:


四、调用 ActivityOptionsCompat

转场动画是在两个界面的跳转返回时发生的,所以,当使用 intent 跳转界面时,需要调用 ActivityOptionsCompat来指定动画的运行。

一般来说,调用 ActivityOptionsCompat 的模板代码如下:

// 创建一个包含过渡动画信息的 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());

ActivityOptionsCompat 是在support v4 包里面的,其实它是 ActivityOptions 的一个兼容(ActivityOptions是API 16引入的)。

然后,我们需要在第二个 Activity 中,将转场的图片获取并显示到界面中。

多个共享元素的过渡实现

有时候我们需要让多个元素产生动画效果,可以使用 Pair<> 来实现:

ActivityOptions optiOns= ActivityOptions.makeSceneTransitionAnimation(this, Pair.create(view1, "agreedName1"), Pair.create(view2, "agreedName2"));

五、手动实现一个转场动画

现在市面上,Android 5.0 以下的手机系统还有一定的市场份额,所以为了照顾这些用户,我们只能手动实现一下共享元素的转场动画效果。

实现的思路也比较简单,大概的步骤如下:

        1、确定第一个界面的共享元素,将其信息传递个第二个界面

        2、第二个界面接收信息,开始的时候将界面设置为透明,并只显示共享元素。

        3、将第二个界面的共享元素进行动画处理。

那么我们开始一步步实现上面的步骤。

获取共享元素位置信息

在第一个界面中,我们需要获取到共享元素的位置信息,并将其传递给下一个界面。于是乎,我们可以在第一个界面元素点击事件中,这么写:

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);
}

其中,getGlobalVisibleRect() 方法的含义是,获取 可见的状态栏高度+可见的标题栏高度+Rect左上角到标题栏底部的距离,如果标题栏被隐藏了,那么可见标题栏高度为0。

接下来,就在在第二个界面接收位置信息并将该图片展示出来了。

模拟转场动画

在第二个界面中,我们需要做如下的操作:

       1、获取上共享元素信息。

       2、计算共享元素缩放比例和位移距离。

       3、调用动画,完成模拟转场效果。

我将上面三个步骤的代码如下。

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)));
}

在12行,通过设置 Margin 的形式来确定图片的位置,需要注意的是,由于状态栏是在父控件 FramLayout 之外的,因此我们要将 Rect.top 的值减去状态栏的高度,这样才是相对于屏幕的绝对位置。然后,getBundleInfo() 方法的代码如下:

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));
}

动画处理

最后我们需要使用动画来模拟转场效果,代码如下:

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();
}

很简单,自此,入场动画效果基本模拟完毕。

而退场动画就更简单了,直接上代码:

private void runExitAnim() {
 mImageView.animate()
    .setInterpolator(DEFAULT_INTERPOLATOR)
    .setDuration(DURATION)
    .scaleX(1)
    .scaleY(1)
    .translationX(0)
    .translationY(0)
    .withEndAction(new Runnable() {
     @Override
     public void run() {
      finish();
      overridePendingTransition(0, 0);
     }
    })
    .start();
}

总结

以上就是Android中实现转场动画的全部内容,所以,是不是很简单?希望这篇文章的内容对各位Android开发者们能有所帮助,如果有疑问大家可以留言交流。


推荐阅读
  • 深入理解OAuth认证机制
    本文介绍了OAuth认证协议的核心概念及其工作原理。OAuth是一种开放标准,旨在为第三方应用提供安全的用户资源访问授权,同时确保用户的账户信息(如用户名和密码)不会暴露给第三方。 ... [详细]
  • 2023 ARM嵌入式系统全国技术巡讲旨在分享ARM公司在半导体知识产权(IP)领域的最新进展。作为全球领先的IP提供商,ARM在嵌入式处理器市场占据主导地位,其产品广泛应用于90%以上的嵌入式设备中。此次巡讲将邀请来自ARM、飞思卡尔以及华清远见教育集团的行业专家,共同探讨当前嵌入式系统的前沿技术和应用。 ... [详细]
  • 本文详细分析了JSP(JavaServer Pages)技术的主要优点和缺点,帮助开发者更好地理解其适用场景及潜在挑战。JSP作为一种服务器端技术,广泛应用于Web开发中。 ... [详细]
  • 本文总结了2018年的关键成就,包括职业变动、购车、考取驾照等重要事件,并分享了读书、工作、家庭和朋友方面的感悟。同时,展望2019年,制定了健康、软实力提升和技术学习的具体目标。 ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
  • 如何在WPS Office for Mac中调整Word文档的文字排列方向
    本文将详细介绍如何使用最新版WPS Office for Mac调整Word文档中的文字排列方向。通过这些步骤,用户可以轻松更改文本的水平或垂直排列方式,以满足不同的排版需求。 ... [详细]
  • 理解存储器的层次结构有助于程序员优化程序性能,通过合理安排数据在不同层级的存储位置,提升CPU的数据访问速度。本文详细探讨了静态随机访问存储器(SRAM)和动态随机访问存储器(DRAM)的工作原理及其应用场景,并介绍了存储器模块中的数据存取过程及局部性原理。 ... [详细]
  • 几何画板展示电场线与等势面的交互关系
    几何画板是一款功能强大的物理教学软件,具备丰富的绘图和度量工具。它不仅能够模拟物理实验过程,还能通过定量分析揭示物理现象背后的规律,尤其适用于难以在实际实验中展示的内容。本文将介绍如何使用几何画板演示电场线与等势面之间的关系。 ... [详细]
  • 本文介绍如何通过Windows批处理脚本定期检查并重启Java应用程序,确保其持续稳定运行。脚本每30分钟检查一次,并在需要时重启Java程序。同时,它会将任务结果发送到Redis。 ... [详细]
  • MySQL中枚举类型的所有可能值获取方法
    本文介绍了一种在MySQL数据库中查询枚举(ENUM)类型字段所有可能取值的方法,帮助开发者更好地理解和利用这一数据类型。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • 本文详细探讨了在Android 8.0设备上使用ChinaCock的TCCBarcodeScanner进行扫码时出现的应用闪退问题,并提供了解决方案。通过调整配置文件,可以有效避免这一问题。 ... [详细]
  • 本章将深入探讨移动 UI 设计的核心原则,帮助开发者构建简洁、高效且用户友好的界面。通过学习设计规则和用户体验优化技巧,您将能够创建出既美观又实用的移动应用。 ... [详细]
  • 本文介绍如何在应用程序中使用文本输入框创建密码输入框,并通过设置掩码来隐藏用户输入的内容。我们将详细解释代码实现,并提供专业的补充说明。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
author-avatar
彭润昕_149
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有