How to access or reference Buttons/Views dynamically (Android)?

Viewed 19

I have a set of 20 XML buttons that I need to access to programmatically change their margins based on a toggle. After heavy research and tons of failed attempts, I was finally able to manipulate them all perfectly without ruining other non-margin parameters like constraints, like this:

private fun setMargin(sizeInDP: Int) {

        val marginInDp = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP,
            sizeInDP.toFloat(),
            resources.displayMetrics
        ).toInt()

        var parameters = binding.buttonClear.layoutParams as ConstraintLayout.LayoutParams
        parameters.setMargins(
            parameters.leftMargin, marginInDp, parameters.rightMargin, marginInDp
        ) // left, top, right, bottom
        binding.buttonClear.layoutParams = parameters

        parameters = binding.buttonEquals.layoutParams as ConstraintLayout.LayoutParams
        parameters.setMargins(
            parameters.leftMargin, marginInDp, parameters.rightMargin, marginInDp
        ) // left, top, right, bottom
        binding.buttonEquals.layoutParams = parameters

// (... 20 total)

        parameters = binding.buttonZero.layoutParams as ConstraintLayout.LayoutParams
        parameters.setMargins(
            parameters.leftMargin, marginInDp, parameters.rightMargin, marginInDp
        ) // left, top, right, bottom
        binding.buttonZero.layoutParams = parameters
}

However, this creates 119 lines of repeated code. I tried several ways, like iterating over an array with a for loop or a function, but in both of these I was unable to access my actual XML buttons. Two of my best attempts:

        for (button in buttonsArray) {
        val parameters = button.layoutParams as ConstraintLayout.LayoutParams
        parameters.setMargins(
            parameters.leftMargin, marginInDp, parameters.rightMargin, marginInDp
        ) // left, top, right, bottom

        binding.{ button.id } = parameters // this does not work
 }
        fun test(myButton){
            val parameters = myButton.layoutParams as ConstraintLayout.LayoutParams
            parameters.setMargins(
                parameters.leftMargin, marginInDp, parameters.rightMargin, marginInDp
            ) // left, top, right, bottom

            binding.{ myButton.id } = parameters // this does not work

        }

        test(binding.buttonClear.layoutParams) 
        test(binding.buttonEquals.layoutParams)
// (... 20 total)
        test(binding.buttonBackspace.layoutParams) 

In the last example, I know 'myButton' is just a local copy of the button inside test(), so assigning parameters to it would not work. Same with the array, assigning to 'button' just assigns to the array element, not the XML button.

The problem is trying to access/reference the XML button dynamically, I honestly have no idea how. Is something similar to this

binding.{ button.id } = parameters

even possible? If so, how?

1 Answers

Found the solution:

private fun setMargin(sizeInDP: Int) {

// translates DP value to px value for .setMargins() method
        val marginInDp = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP,
            sizeInDP.toFloat(),
            resources.displayMetrics
        ).toInt()

        fun setParams(button: Button) {
            val parameters = button.layoutParams as ConstraintLayout.LayoutParams
            parameters.setMargins(
                parameters.leftMargin, marginInDp, parameters.rightMargin, marginInDp
            ) // left, top, right, bottom

            button.layoutParams = parameters
        }

        setParams(binding.buttonClear)
        setParams(binding.buttonEquals)

// (... 20 total)

        setParams(binding.buttonBackspace)
}

There were two issues, first I was passing binding.buttonClear.layoutParams instead of just passing the button alone. Second, I thought the argument button I was passing to setParams() (or test() in original post) was a local copy inside the function instead of a reference, when in fact it is a reference to the original XML button I pass to the function. Newbie mistake!

If you want to change the margins in a button, this function I made should work plug and play for a button inside a ConstraintLayout. I suppose it would also work for other layout types if you change the ConstraintLayout.LayoutParams to the one in your application, and also change the parameters inside .setMargins() as mine only changes top and bottom margins.

Related