1,需求
这里是需要写一个dialog,添加一个动画。要求:弹出时从外部控件处放大显示,几秒后缩小隐藏到外部控件出。
2,实现
这里只需要使用一个组合动画就行实现想要的效果,效果如下(控件在屏幕右下方):
1,创建一个dialog
代码中添加了,显示及隐藏动画
class TestDialog(context: Context) : Dialog(context, R.style.Dialog) {
private var showAnimSet: AnimatorSet? = null
private var dismissAnimSet: AnimatorSet? = null
/**
* 动画时间
*/
private val DEFAULT_DURATION: Long = 800
private var transX: Float = 0f
private var transY: Float = 0f
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.dialog_test)
}
/**
* show之后,先隐藏布局,通过动画展来展示布局
*/
override fun show() {
try {
super.show()
val contentView = findViewById<View>(R.id.dialog_test)
contentView?.visibility = View.INVISIBLE
showAnim()
} catch (e: Throwable) {
e.printStackTrace()
}
}
/**
* 延时隐藏
*/
fun dismissView(){
Handler().postDelayed({dismissAnim()},3000)
}
override fun dismiss() {
try {
super.dismiss()
} catch (e: Throwable) {
e.printStackTrace()
}
}
/**
* 显示动画
*/
private fun showAnim() {
val contentView = findViewById<View>(R.id.dialog_test) ?: return
if (showAnimSet == null) {
showAnimSet = AnimatorSet()
val transXAnim = ObjectAnimator.ofFloat(contentView, "translationX", transX, 0f)
val transYAnim = ObjectAnimator.ofFloat(contentView, "translationY", transY, 0f)
val scaleXAnim = ObjectAnimator.ofFloat(contentView, "scaleX", 0f, 1f)
val scaleYAnim = ObjectAnimator.ofFloat(contentView, "scaleY", 0f, 1f)
showAnimSet?.playTogether(transXAnim, transYAnim, scaleXAnim, scaleYAnim)
showAnimSet?.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationStart(animation: Animator) {
super.onAnimationStart(animation)
contentView.visibility = View.VISIBLE
dismissView()
}
})
showAnimSet?.duration = DEFAULT_DURATION
}
if (showAnimSet?.isRunning == true) {
return
}
showAnimSet?.start()
}
/**
* 隐藏动画
*/
fun dismissAnim() {
val contentView = findViewById<View>(R.id.dialog_test) ?: return
if (dismissAnimSet == null) {
dismissAnimSet = AnimatorSet()
val transXAnim = ObjectAnimator.ofFloat(contentView, "translationX", 0f, transX)
val transYAnim = ObjectAnimator.ofFloat(contentView, "translationY", 0f, transY)
val scaleXAnim = ObjectAnimator.ofFloat(contentView, "scaleX", 1f, 0f)
val scaleYAnim = ObjectAnimator.ofFloat(contentView, "scaleY", 1f, 0f)
dismissAnimSet?.playTogether(transXAnim, transYAnim, scaleXAnim, scaleYAnim)
dismissAnimSet?.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
dismiss()
}
})
dismissAnimSet?.duration = DEFAULT_DURATION
}
if (dismissAnimSet?.isRunning == true) {
return
}
dismissAnimSet?.start()
}
/**
* show之前调用
*/
fun setAnchorInfo(view:View) {
val location = IntArray(2)
view.getLocationOnScreen(location)
val x = location[0]
val y = location[1]
// 获取的值为px,需要转换单位
transX = (x + view.width).pxToDp(context).toFloat()
transY = y.pxToDp(context).toFloat()
}
}
2,使用setAnchorInfo传入外部控件
此处使用时注意setAnchorInfo方法需要在show()之前调用,这里请确保传入view的宽高位置等属性已经可以获取(即布局绘制的onLayout()方法之后)
使用实例:
dialog = TestDialog(this@MainActivity)
findViewById<Button>(R.id.test_button).let {
it.setOnClickListener {
dialog?.show()
}
}
findViewById<Button>(R.id.test_button).post {
dialog?.setAnchorInfo(findViewById<Button>(R.id.test_button))
}
3,结言
这里只是粗略的实现了动画效果,弹出的锚点位置需根据需求自行调节,修改setAnchorInfo()方法中的计算方法即可