Search code examples
androidanimationkotlinpositionandroid-animation

Animation moves View to wrong position


I want to move an ImageView to the center of a Button. For doing so, I use the following code:

    var leftPos = mButtonView.left.toFloat()
    var rightPos = mButtonView.right.toFloat()
    var topPos = mButtonView.top.toFloat()
    var bottomPos = mButtonView.bottom.toFloat()

    var centerX = (leftPos + rightPos)/2
    var centerY = (topPos + bottomPos)/2

    var soultoX = ObjectAnimator.ofFloat(mContentView, "x", centerX).apply {
        duration = 1000
    }

    var soultoY = ObjectAnimator.ofFloat(mContentView, "y", centerY).apply {
        duration = 1000
    }

    fun soulToButton() = AnimatorSet().apply {
        play(soultoX).with(soultoY)
        start()
    }

On calling soulToButton(), instead of moving to the expected point in the middle of mButtonView, mContentView moves to the upper left corner of the screen. Any idea why?


Solution

  • I think the problem is - finding the coordinates/size of an Android View during screen construction. To get the coordinates/size of a View as soon as it is known, attach a listener to its ViewTreeObserver.

    For example:

       override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            val buttonView = btn
            val contentView = img
    
            object : ViewTreeObserver.OnGlobalLayoutListener {
                override fun onGlobalLayout() {
                    contentView.viewTreeObserver.removeOnGlobalLayoutListener(this)
    
                    var leftPos = buttonView.left.toFloat()
                    var rightPos = buttonView.right.toFloat()
                    var topPos = buttonView.top.toFloat()
                    var bottomPos = buttonView.bottom.toFloat()
    
                    var centerX = (leftPos + rightPos - contentView.width) / 2
                    var centerY = (topPos + bottomPos - contentView.height) / 2
    
                    var soultoX = ObjectAnimator.ofFloat(contentView, "x", centerX).apply {
                        duration = 1000
                    }
    
                    var soultoY = ObjectAnimator.ofFloat(contentView, "y", centerY).apply {
                        duration = 1000
                    }
    
                    fun soulToButton() = AnimatorSet().apply {
                        play(soultoX).with(soultoY)
                        start()
                    }
    
                    soulToButton()
                }
            }.run {
                contentView.viewTreeObserver.addOnGlobalLayoutListener(this)
            }
        }