使用揭露动画,让你的应用特效更进一步!,美团安卓面试

第一个参数是个 View,揭露动画的应用对象必须是一个 View,这点不难理解。

第二个参数是圆形揭露效果的圆心 X 轴坐标,同理第三个参数是 Y 轴坐标。

第三个参数是圆形揭露效果的开始半径,同理第三个参数是圆形揭露效果的终止半径,开始半径传 0,终止半径传 View 的宽度或高度就是个典型的从无到有的揭露(显示)过程,反之,开始半径传 View 的宽度或高度,终止半径传 0 就是个从有到无的反揭露(隐藏)过程。

拿到此方法返回的 Animator 对象我们就可以随时控制 View 进行揭露动画了。

是不是很简单?

View  级别的揭露动画

我们先来看看最简单的普通 View 的揭露动画效果(上面第三张图)其具体代码是怎样的。

/* Demo 的关键代码文件结构

appreveal

│  MainActivity.kt

│  SecondActivity.kt //普通 View 的揭露效果见 Demo 里的这个文件中的代码

├─base

│      BaseActivity.kt //Activity 和 App 层面的揭露动画效果主要见 Demo 里此文件中的代码

├─ext

│      ActicityExtension.kt

└─util

StatusBarUtil.kt

*/

普通 View 的揭露动画见 Demo 里的 SecondActivity,其布局如下:

<?xml version="1.0" encoding="utf-8"?>

<androidx.constraintlayout.widget.ConstraintLayout

xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:app=“http://schemas.android.com/apk/res-auto”

xmlns:tools=“http://schemas.android.com/tools”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:background=“@android:color/white”

tools:context=“.SecondActivity”>

<View

android:id=“@+id/viewBg”

android:layout_width=“0dp”

android:layout_height=“0dp”

app:layout_constraintStart_toStartOf=“parent”

app:layout_constraintEnd_toEndOf=“parent”

app:layout_constraintTop_toTopOf=“parent”

app:layout_constraintBottom_toBottomOf=“parent”

android:background=“@android:color/holo_blue_bright”

android:visibility=“visible”/>

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

app:layout_constraintStart_toStartOf=“parent”

app:layout_constraintEnd_toEndOf=“parent”

app:layout_constraintTop_toTopOf=“parent”

app:layout_constraintBottom_toBottomOf=“parent”

app:layout_constraintVertical_bias=“0.1”

android:text=“@string/app_second”

android:textSize=“30sp”/>

<Button

android:id=“@+id/btnReveal”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“@string/app_reveal_r”

app:layout_constraintBottom_toBottomOf=“parent”

app:layout_constraintLeft_toLeftOf=“parent”

app:layout_constraintRight_toRightOf=“parent”

app:layout_constraintTop_toTopOf=“parent” />

</androidx.constraintlayout.widget.ConstraintLayout>

SecondActivity 中设置点击中间的按钮开始 id 为 viewBg 界面控件的揭露动画,关键代码如下:

//中间按钮的点击事件

btnReveal.setOnClickListener { view ->

//系统提供的揭露动画需 5.0 及以上的 sdk 版本

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {

return@setOnClickListener

}

//动画开始半径和结束半径,两者相对关系可用于控制是揭露还是反揭露,也即是从无到有还是从有到无

val startRadius:Float

val endRadius:Float

if (viewBg.visibility == View.VISIBLE){

//从有到无,即反揭露

startRadius = viewBg.height.toFloat()

endRadius = 0f

}else{

//从无到有,即揭露效果

startRadius = 0f

endRadius = viewBg.height.toFloat()

}

val location = IntArray(2)

view.getLocationInWindow(location)

//关键代码,构建一个揭露动画对象,注意圆形揭露动画的圆心以及开始半径和结束半径是如何计算出来的,应该很好理解,这里不做过多解释

val animReveal = ViewAnimationUtils.createCircularReveal(viewBg,

location[0] + view.width/2,

location[1] + view.height/2,

startRadius,

endRadius

)

//构建好了揭露动画对象,开始设置动画的一些属性和相关监听

animReveal.duration = 400

animReveal.interpolator = LinearInterpolator()

animReveal.addListener(onStart = {

viewBg.visibility = View.VISIBLE

},onEnd = {

if (startRadius != 0f){

viewBg.visibility = View.INVISIBLE

btnReveal.setText(R.string.app_reveal)

}else{

viewBg.visibility = View.VISIBLE

btnReveal.setText(R.string.app_reveal_r)

}

})

animReveal.start()

}

代码真机运行的具体界面效果如下:

基本使用如此,为界面中的某个 View 应用揭露动画效果还是很简单的,下面我们看看如何为应用内 Activity 间的切换(上面Activity 的揭露效果一图)应用我们炫酷(主观上的)的揭露动画效果。

Activity 级别的揭露动画

首先我们会遇到两个问题:

  1. 揭露动画用于 Activity 切换时,我们该把揭露动画应用于哪个 View(揭露动画的应用对象必须是一个 View)?

  2. 何时开始执行揭露动画?

根据我们得 Demo,一一作答。

揭露动画用于 Activity 切换时,最合适的对象肯定是此 Activity 相关 Window 的根视图,真正的根视图,没错正是此 Activity 的 Window 的  DecorView。

至于揭露动画的开始时机,太早或太晚都不好。首先不能太早,如果当前 View 还未 Attach 到 Window 上就对其应用揭露动画会抛出异常,其次不能太晚,不然会严重影响动画的视觉效果。

经作者实践,这个最好的揭露动画开始时机在视图的可见性刚变为对用户可见时最佳!我们通过为 View 的  ViewTreeObserver  设置一个 OnGlobalLayoutListener 回调可完美监听到这个最佳时机~

我把相关实现代码全都放在了 Demo 的 BaseActivity 类里,用例 Activity 只要继承 BaseActivity 即可在打开时应用揭露动画效果。这里注意为了动画的连贯性我们需要把 Activity 揭露动画开始的圆心坐标从它的上个 Activity 里通过 Intent 传递过来,这点并不难实现。关键代码如下:

//将 Activity 的揭露效果写在 Base 类中,需要揭露动画效果时继承

abstract class BaseActivity : AppCompatActivity(){

companion object {

//手动往 intent 里传入上个界面的点击位置坐标

val CLICK_X = “CLICK_X”

val CLICK_Y = “CLICK_Y”

}

private var onGlobalLayout : ViewTreeObserver.OnGlobalLayoutListener? = null

//揭露(进入)动画

var mAnimReveal : Animator? = null

//反揭露(退出)动画

var mAnimRevealR : Animator? = null

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

circularReveal(intent)

}

//Activity 揭露(进入)动画,进入时使用

private fun circularReveal(intent: Intent?){

//系统提供的揭露动画需 5.0 及以上的 sdk 版本,当我们获取不到上个界面的点击区域时就不展示揭露动画,因为此时没有合适的锚点

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ||

(intent?.sourceBounds == null && intent?.hasExtra(CLICK_X)?.not()?:true)) return

val rect = intent?.sourceBounds

val v = window.decorView

v.visibility = View.INVISIBLE

@SuppressWarnings

onGlobalLayout = object : ViewTreeObserver.OnGlobalLayoutListener{

override fun onGlobalLayout() {//此时既是开始揭露动画的最佳时机

mAnimReveal?.removeAllListeners()

mAnimReveal?.cancel()

mAnimReveal = ViewAnimationUtils.createCircularReveal(v,

rect?.centerX()?:intent?.getIntExtra(CLICK_X, 0)?:0,

rect?.centerY()?:intent?.getIntExtra(CLICK_Y, 0)?:0,

0f,

v.height.toFloat()

)

mAnimReveal?.duration = 400

mAnimReveal?.interpolator = LinearInterpolator()

mAnimReveal?.addListener(onEnd = {

onGlobalLayout?.let {

//我们需要在揭露动画进行完后及时移除回调

v?.viewTreeObserver?.removeOnGlobalLayoutListener(it)

}

})

mAnimReveal?.start()

}

}

//视图可见性发生变化时的回调,回调里正是开始揭露动画的最佳时机

v.viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayout)

}

//Activtiy 反揭露(退出)动画,即退出时的过渡动画,

//这么起名可能不恰当,其实还是同样的动画,

//只不过揭露的起始和终结半径跟上面相比反过来了

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

总结

本文讲解了我对Android开发现状的一些看法,也许有些人会觉得我的观点不对,但我认为没有绝对的对与错,一切交给时间去证明吧!愿与各位坚守的同胞们互相学习,共同进步!

54)]
[外链图片转存中…(img-8ofZFYuv-1711825672855)]
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-NfEJub2h-1711825672855)]

总结

本文讲解了我对Android开发现状的一些看法,也许有些人会觉得我的观点不对,但我认为没有绝对的对与错,一切交给时间去证明吧!愿与各位坚守的同胞们互相学习,共同进步!

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值