Search code examples
androidandroid-relativelayoutcustom-view

Calling setLayoutParams() in onLayout method of custom view group does nothing


I'm extending RelativeLayout and want to set position of my childViews in onLayout method. So here is the code:

 override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {

    val margin = Math.round(beautyButton!!.measuredWidth * 1.75).toInt()

    beautyButton!!.visibility = View.GONE

    var params = defaultSeekbar!!.layoutParams as RelativeLayout.LayoutParams
    params.setMargins(margin,0,margin,0)
    params.addRule(CENTER_IN_PARENT)
    params.removeRule(ALIGN_PARENT_START)
    params.removeRule(START_OF)

    var params2 = beautySeekbar!!.layoutParams as RelativeLayout.LayoutParams
    params2.setMargins(margin,0,margin,0)
    params2.addRule(CENTER_IN_PARENT)
    params2.removeRule(ALIGN_PARENT_START)
    params2.removeRule(START_OF)

   super.onLayout(changed, l, t, r, b)
}

I want to set position of seekbars depending on size of Button. And this does nothing. I also tried something like this, but result is the same.

defaultSeekbar!!.layout(margin,defaultSeekbar!!.measuredWidth,margin,defaultSeekbar!!.measuredHeight)

Can someone help me please to figure out how can I set position of my child views before drawing them to screen?

Thanks everyone for the answers in advance!


Solution

  • You're missing a bit of code. You can't just retrieve a View's LayoutParams and then modify them, as the framework needs some way to know they've been updated.

    Add these lines:

    defaultSeekbar!!.layoutParams = params
    beautySeekbar!!.layoutParams = params2
    

    Remember, Kotlin likes to convert Java setter/getter methods to what it calls the Property Access Syntax, where they look like variables. The catch is that View#setLayoutParams() doesn't just change a variable in View. It also calls some other stuff so the framework knows that that View has been changed.

    Another thing. I'm guessing you're doing the !! because you're not initializing the SeekBars immediately. You can use the lazy init syntax, if it works for your situation (I can't tell because you haven't posted that code):

    defaultSeekbar by lazy { findViewById<WhateverClass>(R.id.whatever) }
    beautySeekbar by lazy { findViewById<WhateverClass>(R.id.whatever2) }
    

    They'll only be initialized once they're called, and then that instance will remain.