ValueAnimator中ofObject、ofInt()的使用场景

132 阅读2分钟

最近有个需求点击显示信息还要有动画效果实现,一开始就想到使用dialog来实现,再百度一下动画效果的方法就能实现,但是效果没达到,记录一下。

 val mOperationDialog = OperationDialog(this)
        val window: Window = mOperationDialog.window!!
        val wlp: WindowManager.LayoutParams = window.attributes
        wlp.gravity = Gravity.BOTTOM
//        val screenHeight: Int = window.windowManager.defaultDisplay.height
        wlp.width = WindowManager.LayoutParams.MATCH_PARENT
        wlp.height = WindowManager.LayoutParams.WRAP_CONTENT
        wlp.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL //设置穿透效果,dialog之外可以相应事件传递
        window.attributes = wlp
        window.setDimAmount(0f)
        window.setBackgroundDrawableResource(R.color.transparent)
        window.setWindowAnimations(R.style.MyDialogAnimation)
        mOperationDialog.setCanceledOnTouchOutside(false)  //设置点击dialog以外的区域不会导致dialog消失
//        mTrackList?.let { mOperationDialog.setData(it) }
        mOperationDialog.show()
        dismissDialog.setOnClickListener {
            mOperationDialog.dismiss()
        }
        showDialog.setOnClickListener {
            mOperationDialog.show()
        }

最开始想到的就是创建一个Dialog来显示,点击dialog布局内的按钮达到整个dialog的window的下降和上升

down_arrow.setOnClickListener {
    show = !show
    if (show){
        ll_view.animateScrollY2(600,110,1000)
        down_arrow.setImageResource(R.mipmap.up_arrow)
    }else{
        ll_view.animateScrollY2(110,600,1000)
        down_arrow.setImageResource(R.mipmap.down_arrow)
    }
}
@SuppressLint("ViewConstructor")
class ArrowScrollView(context: Context?, attrs: AttributeSet?)
    : LinearLayout(
    context,
    attrs
) {

    private val mScroller: Scroller = Scroller(context)
    override fun computeScroll() {
        super.computeScroll()
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.currX, mScroller.currY)
            postInvalidate()
        }
    }
    fun animateScrollY0(startY: Int, endY: Int, duration: Int) {
        val valueAnimator: ValueAnimator = ValueAnimator.ofInt(startY, endY)
        valueAnimator.addUpdateListener { animator ->
            val scrollY = animator.animatedValue as Int
            scrollTo(0, scrollY)
        }
        valueAnimator.duration = duration.toLong()
        valueAnimator.start()
    }

    fun animateScrollY1(startY: Int, endY: Int, duration: Int) {
        var dy = endY - startY
        if (dy > 0){
            mScroller.startScroll(0, -dy, 0, dy, duration)
        }else{
            mScroller.startScroll(0, 0, 0, dy, duration)
        }
        Log.d("ceshiy1","$startY")
        Log.d("ceshiy2","$dy")
        Log.d("ceshiy3","$endY")
        invalidate()
    }

    @SuppressLint("Recycle")
    fun animateScrollY2(startY: Int, endY: Int, duration: Int) {
        val evaluator: TypeEvaluator<ViewGroup.LayoutParams> = HeightEvaluator()
        val start = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, startY)
        val end = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, endY)
        val valueAnimator: ValueAnimator = ObjectAnimator.ofObject(ll_view,"layoutParams",evaluator, start, end)
        val set = AnimatorSet()
        set.play(valueAnimator)
        valueAnimator.duration = duration.toLong()
        valueAnimator.start()
    }

    internal inner class HeightEvaluator :
        TypeEvaluator<ViewGroup.LayoutParams> {
        override fun evaluate(
            fraction: Float,
            startValue: ViewGroup.LayoutParams,
            endValue: ViewGroup.LayoutParams
        ): ViewGroup.LayoutParams {
            val params = ll_view!!.layoutParams
            params.height =
                (startValue.height + fraction * (endValue.height - startValue.height)).toInt()
            return params
        }
    }
}

最开始使用的是animateScrollY0方法,即ValueAnimator.ofInt,传入动画起始y的坐标和动画终止y的坐标,将监听器添加到在动画生命周期中发送更新事件的监听器集。在计算出动画的值后,该方法将在动画的每一帧的所有侦听器上调用,animator就是每一帧动画更新的值,scrollTo()滚动到该值。实现后的效果如下。

image.png

然后上网查询使用animateScrollY1()方法效果和上面的一样。才知道是我的参数传错了,修改了参数并且使用了ObjectAnimator.ofObject()方法传递ViewGroup.LayoutParams()参数并使用估值器来改变ViewGroup.LayoutParams.height 效果是达到了,但是dialog的动画流畅度不够,最后取消了dialog的实现方法,直接将dialog的布局写入根布局,再使用animateScrollY1()方法得以完美实现动画效果。

最后总结一下:dialog有自己动画弹出方法:window.setWindowAnimations(R.style.MyDialogAnimation),这个方法只能是dialog外部按钮点击实现dialog显示和消失,像这个需求需要再dialog内部设置一个按钮点击按钮实现dialog局部布局的隐藏和显示就不行了,这个需求使用ObjectAnimator.ofObject()方法的动画效果的流畅度不够,最后放弃使用dialog直接使用将dialog布局写入根布局下就很好的解决问题了,其实有时候问题可以用很简单的方法解决但是可能陷入牛角尖里面就很难再出来了。