1

I need to know the size of a Button (or any other view). But none of the procedures in lifecycle (onCreate, onStart, OnResume) seem to know it, as the Button seems not yet to be initialized!

...
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    private var servOffset: Int=0  // Value depends on Layout/Orientation and Device

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        btPunkte.setOnClickListener { doPunkt(true) }
        servOffset = btPR1.width/2  // 'btPR1' is a Button in 'Layout activity_main.*'
        //ToDo: Doesn't work! = remains 0 
    }

    override fun onResume() {
        super.onResume()
        // ToDo: unsolved! When do I get the size?? 
        //     onStart (or onResume) are invoked correctly, but don't know the value!
        //     ?? Button doesn't yet exist in Livecycle?!
        servOffset = btPR1.width/2  // //ToDo: Still doesn't work!  
        anzeigeAktualisieren()
    }

    private fun anzeigeAktualisieren() {
        // If ... move Button
        btPR1.x += servOffset //ToDo: unsolved offset remains 0 ?!
    }

    private fun doPunkt(links:Boolean) {
        anzeigeAktualisieren()
        ...
    }
...
}

I did find "When are views drawn", and several other threads, but they didn't help me solve my problem.

Aquaball
  • 111
  • 1
  • 5
  • What happens if you use the Kotlin equivalent of `getMeasuredWidth()` instead? (maybe just `measuredWidth` in Kotlin but the documentation does not tell :( ) – Bö macht Blau Apr 20 '18 at 18:39
  • Thx for the hint. But value still remains 0. Just to be clear: later (after any click) the values are read properly (width and measuredWidth). – Aquaball Apr 21 '18 at 11:31
  • So if I understand you correctly in order to assign a new position to the Button you need to determine the correct value for servOffset. This value depends on how wide the Button will actually be. If I'm right so far then you should indeed use a ViewTreeObserver/ OnGlobalLayoutListener. At the moment the listener fires, the measured width of the Button will calculated. This is the earliest point in time when you can set a value to servOffset. But don't use the code from the answer (bad practice indeed), rather take a look at the link I posted in my comment. – Bö macht Blau Apr 21 '18 at 14:33
  • Exactly right! I've already implemented your link's advice (Observer/ Listener, including Remove) and works fine (but only:) AFTER the first Click. On first displaying the layout the servOffset is still '=0'. – Aquaball Apr 21 '18 at 15:20

1 Answers1

0

You can try using viewTreeObserver.

val vto = button.viewTreeObserver
vto.addOnGlobalLayoutListener {
    Log.e("Show me width", button.width.toString())
}

It is working, but it can and WILL be called several times!!!

Other option is to use Handler and postDelayed

 Handler().postDelayed({
        Log.e("Show me width2", button.width.toString())
    }, 1000)

Yes, this is very bad practice, but it can save you in stupid situation :)

Good luck!

  • Thx for your help. Unfortunately it does neither solve the problem, nor answer the question. It helps a little, as AFTER the first clicking (doPunkte) the value is set correctly. But not at initial displaying the layout. (onResume, anzeigeAktualisieren). – Aquaball Apr 20 '18 at 13:50
  • Just about the use of `ViewTreeObserver`: It is a little less of a bad practice if you remove the `OnGlobalLayoutListener` as soon as possible, see for example [here](https://stackoverflow.com/a/7735122/5015207) – Bö macht Blau Apr 20 '18 at 18:46