How to restore translationX of custom view on Android

185 Views Asked by At

I have a custom tab view derived from LinearLayout which inflates an xml layout. Inside it I have a view (llIndicator) which is used as an indicator bar and I achive this with animating the translationX property of the view like this:

val offset = llIndicator.width * activeTabIndex
llIndicator.animate().translationX(offset.toFloat())

It all works fine, the only problem is when I am trying to restore the state of the view after activity is destroyed and re-created. Most of the properties does not even need to be saved because the setup code in the fragment is called again, but i would like to save the selected tab and restore the translationX property and restore it without animation.

But I cannot seem to find the correct solution. I save the selected tab to a bundle, successfully restore it, calculate the correct position, but when I set the translationX property, it does not do anything...

It does not work if I do it in the onRestoreInstanceState() method because it happens before the layout, so I tried to set an isInstanceBeingRestored variable to true in the onRestoreInstanceState() and set translationX in the onLayout() method, but with no success.

So i tried using an OnGlobalLayoutListner() as well by placing the following code in the init{ } of the view.

viewTreeObserver.addOnGlobalLayoutListener(object: ViewTreeObserver.OnGlobalLayoutListener{
        override fun onGlobalLayout() {
            viewTreeObserver.removeOnGlobalLayoutListener(this)
            // Restore view if needed
            if(isInstanceBeingRestored){
               llIndicator.translationX = offset                       
            }
        }
    })

It still does nothing... offset is correctly calculated, I checked by using Log.d(), and also replacing it with by any number has no effect.

So I tried using the post() method, as following:

 llIndicator.post({
       llIndicator.translationX = offset
 })

I tried placing it in the onLayout() method (of course checking the isInstanceBeingRestored variable first) and also to the OnGlobalLayoutListener() but no effect.

But what is interesting, if I use postDelayed() with a large enough delay, it works.

 llIndicator.postDelayed({
       llIndicator.translationX = offset
 }, 1500)

But obviously, this solution cannot remain, I just tried it out... So I am confused... This sounds quite a simple thing to solve but after hours of Googling and trying different codes, and scratching my head, I still couldn't solve it. Surely it cannot be so difficult, can it?

What am I doing wrong? Can anyone point me in the right direction?

Thank's very much in advance for any help.

Edit:

I found something interesting... If I use marginStart instead of translationX as below to set the position it works. What would be the reason for that? I don't get it...

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
   if(isInstanceBeingRestored){
        val p = llIndicator.layoutParams as MarginLayoutParams
        p.marginStart = offset.toInt()
        llIndicator.layoutParams = p

        //llIndicator.translationX = offset
   }
}

Edit 2: Well it only works with marginStart if the margin start was 0 before activity gets destroyed... So if I set offset to a random value, independent from its previous position, it displays the indicator at the correct position, if marginStart was 0 before... Otherwise the indicator bar appears at the left side of the screen. Now I am getting really lost... I double-checked the calculations but they give the correct offset...

Best wishes, Agoston

0

There are 0 best solutions below