Android中的沉浸式丝滑转场之共享元素转场动画
创始人
2024-11-06 00:10:00

文章目录

    • 1. 介绍
    • 2. 实现方法
    • 3. 举例演示
      • 3.1 举例一:普通页面间共享元素转场动画
      • 3.2 举例二:列表页面共享元素转场动画
    • 4. 总结

1. 介绍

在Android开发中,经常会有页面转场的动画效果。普通的转场动画不过是左进右出,渐显渐隐,局限于整个页面。而对于页面中的某个元素,尤其是图片,如果能很自然的过渡到下一个页面,那么用户体验会非常丝滑。这就是Android中的共享元素动画

来看下效果吧:

  1. 场景一:普通页面间共享元素转场动画
    共享元素转场动画
  2. 场景二:列表页面共享元素转场动画
    共享列表元素转场动画

2. 实现方法

Android中提供了 ActivityOptionsCompat.makeSceneTransitionAnimation 方法来实现场景转场动画,配合xml中的属性android:transitionName,在Activity跳转时指定共享的元素View,生成bundle对象,然后传入startActivity方法中。系统便会自动为你实现上述效果。

比如页面 A 跳到页面 B,共享页面里的两个 ImageView 做动画,那么在页面A startActivity 时,就需要使用ActivityOptionsCompat.makeSceneTransitionAnimation生成 Bundle:

public static ActivityOptionsCompat makeSceneTransitionAnimation(@NonNull Activity activity,             @NonNull View sharedElement, @NonNull String sharedElementName) 

makeSceneTransitionAnimation 方法需要提供三个参数:

  • Activity activity :包含共享元素的 activity,也就是当前 activity;
  • View sharedElement: 需要有共享动画效果的 View,也就是页面A的 ImageView;
  • String sharedElementName: 共享元素的名字,随便起个名字,只要跟目标页面xml里的android:transitionName 一致即可

该方法返回值是 ActivityOptionsCompat,需要调用 toBundle 方法,将其转换为 Activity 间数据传递用的 Bundle 对象。

接着,调用 startActivity(it, bundle) 方法,将bundle 传入即可。

在页面B中,需要有对应的 ImageView,在它的xml布局里,需要添加属性android:transitionName,标明它是目标的共享元素。这样页面A中的 ImageView 就能共享到页面B的 ImageView上了。它们之间的大小位置等差异会以动画的形式自然过渡。

核心代码如下:

 fun jump(view: View) {  	// 生成转场动画的bundle对象     val bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(this, imgView!!, "share_image")             .toBundle()     // 如果有参数传递,可以这么添加     bundle?.putString("key1", "value1")     Intent(this, ShareElementActivity2::class.java).let {         it.putExtras(bundle!!)         startActivity(it, bundle!!)     } } 

xml代码

 

3. 举例演示

接下来,我们用完整的例子来演示共享动画效果。(本案例使用kotlin语言演示,Java也是同理; 本案例中使用到的资源文件test1.jpeg 是一张普通的测速图片,你可以随便找一张图片代替。)

3.1 举例一:普通页面间共享元素转场动画

效果描述:我们将实现两个页面之间的跳转,由 ShareElementActivity1 跳转到 ShareElementActivity2。这两个页面里都有一个 ImageView 展示一张图片,这两张图片的大小位置有差异,前者60x60, 后者200x200。我们要实现的共享动画效果是:页面跳转过程中,这两张图片自然过渡,看起来是前面的小图,自然放大到后者的动画一样,并且整个页面也是自然过渡,没有生硬切换的迹象;页面返回时,大图自然缩小到小图,也是非常自然的动画过渡。具体效果可参考章节1中的效果图。

ShareElementActivity1代码:

import android.content.Intent import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.view.View import android.widget.ImageView import androidx.core.app.ActivityOptionsCompat import com.example.mytest.R  class ShareElementActivity1 : AppCompatActivity() {      private var imgView: ImageView? = null      override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContentView(R.layout.activity_share_element1)         imgView = findViewById(R.id.imageView)     }      fun jump(view: View) {         val bundle =             ActivityOptionsCompat.makeSceneTransitionAnimation(this, imgView!!, "share_image")                 .toBundle()         bundle?.putString("key1", "value1")         Intent(this, ShareElementActivity2::class.java).let {             it.putExtras(bundle!!)             startActivity(it, bundle!!)         }     } } 

对应布局文件:activity_share_element1.xml:

             

目标页面:ShareElementActivity2

import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.view.View import android.widget.ImageView import com.example.mytest.R  class ShareElementActivity2 : AppCompatActivity() {      private var imgView: ImageView? = null      override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContentView(R.layout.activity_share_element2)         imgView = findViewById(R.id.imageView)     }      fun back(view: View) {         // 调用this.finish()不会有共享元素转场退出效果         // this.finish()          // 模拟返回键,调用系统的back按键,会有共享元素转场退出效果         onBackPressed()     } } 

对应布局文件:activity_share_element2.xml

             

注意:
如果要手动从目标页面返回,不能直接调finish方法,那样就不会走系统的共享元素动画了。应该调用系统的back按键onBackPressed,这样就会有共享元素转场退出效果。

3.2 举例二:列表页面共享元素转场动画

接下来再来举个更实用的例子,从列表上点击进入详情页,应该是非常常见的场景。这里更适合这种共享元素无缝切换的效果,给用户的感觉会非常沉浸式。

列表页ShareElementListActivity,这里我们用到了 RecyclerView+Adapter来实现一个简单的列表

import android.content.Intent import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.view.View import android.widget.ImageView import androidx.core.app.ActivityOptionsCompat import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.example.mytest.R import com.example.mytest.recyclerviewclick.RcvAdapter  class ShareElementListActivity : AppCompatActivity() {      private var rcv: RecyclerView? = null     private var adapter: RcvAdapter? = null     private var dataList: MutableList = mutableListOf()      override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContentView(R.layout.activity_share_element_list)         initData()         rcv = findViewById(R.id.rcv)         adapter = RcvAdapter(this, dataList).apply {             onItemClickListener = object: RcvAdapter.OnRcvItemClickListener {                 override fun onItemClicked(position: Int, view: View) {                     val imageView = view.findViewById(R.id.iv_cover)                     val bundle =                         ActivityOptionsCompat.makeSceneTransitionAnimation(this@ShareElementListActivity, imageView!!, "share_image")                             .toBundle()                     Intent(this@ShareElementListActivity, ShareElementActivity2::class.java).let {                         this@ShareElementListActivity.startActivity(it, bundle)                     }                 }              }         }         rcv?.adapter = adapter         rcv?.layoutManager = LinearLayoutManager(this)     }      private fun initData() {         for (i in 0..100) {             dataList.add("条目 $i")         }     } } 

列表数据适配器类:RcvAdapter

import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import android.widget.Toast import androidx.recyclerview.widget.RecyclerView import com.example.mytest.R  class RcvAdapter(val context: Context, val dataList: MutableList) :     RecyclerView.Adapter() {      var onItemClickListener: OnRcvItemClickListener? = null      class RcvViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {          private var container: ViewGroup? = null         private var tvContent: TextView? = null          init {             container = itemView.findViewById(R.id.ll_item_container)             tvContent = itemView.findViewById(R.id.tv_content)         }          fun bind(textContent: String, position: Int) {             tvContent?.text = textContent             container?.isSelected = true         }      }      override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RcvViewHolder {         val view = LayoutInflater.from(context).inflate(R.layout.list_item_layout, parent, false)         return RcvViewHolder(view)     }      override fun onBindViewHolder(holder: RcvViewHolder, position: Int) {         holder.bind(dataList.get(position), position)         holder.itemView.setOnClickListener {             Toast.makeText(it.context, "点击了$position", Toast.LENGTH_SHORT).show()             onItemClickListener?.onItemClicked(position, it)         }     }      override fun getItemCount(): Int {         return dataList.size     }      interface OnRcvItemClickListener {         fun onItemClicked(position: Int, view: View)     } } 

布局文件:

  1. ShareElementListActivity页面布局文件:activity_share_element_list.xml
         
  1. RcvAdapter用到的一个列表Item的布局文件:list_item_layout
                                          

目标页面仍是 ShareElementActivity2,代码在3.1 例子里,不再赘述。

4. 总结

  1. 本文介绍了Android中共享元素转场动画的效果演示,尤其是比较常见的列表页面共享元素转场动画
  2. 介绍了实现方法:通过Android中提供了 ActivityOptionsCompat.makeSceneTransitionAnimation 方法来实现场景转场动画,配合xml中的属性android:transitionName,在Activity跳转时指定共享的元素View,生成bundle对象,然后传入startActivity方法中,系统便会自动为你实现上述效果。
  3. 提供了两个完整的代码示例演示了共享元素转场动画效果,读者可以非常方便的复制代码来实现文章中的效果,不会有那种虎头蛇尾,缺少各种上下文代码的烂尾教程所带来的困扰🤣。

如果你对这篇文章有更好的建议,欢迎评论留言交流;
如果这篇文章对你有用,欢迎支持!感谢支持哦😊~

相关内容

热门资讯

裸辞做“一人公司”,我后悔了 去年这个时候,一位以色列程序员正在东南亚旅行。他顺手把一个在脑子里转了很久的想法做成了产品,一个让任...
南京建成国内首个Pre-6G试... 4月21日,2026全球6G技术与产业生态大会在南京开幕。全息互动技术展台前,一名远在北京的工作人员...
超梵求职受邀参加“2025抖音... 超梵求职受邀参加“2025抖音巨量引擎成人教育行业生态大会”,探讨分享优质内容传播,服务万千学员。 ...
摩托罗拉Razr 2026(R... IT之家 4 月 22 日消息,摩托罗拉宣布新一代 Razr 折叠手机将于 4 月 29 日在美国发...
库克卸任,特纳斯领航:苹果新纪... 苹果首席执行官蒂姆·库克将卸任,硬件工程主管约翰·特纳斯将接任,苹果公司今天宣布此事。 库克将在夏季...