android programatically position dialog under specific view in CustomView

188 Views Asked by At

in android kotlin app I created my own custom spinner (I used dialogFragment for spinner to achieve this). Now when I show it on click, I want it to always be positioned under the specific view in my CustomView in which I open this spinnerDialog.

My code goes like this:

 private fun openSpinnerDialog() {
        binding?.let {
            val location = IntArray(2)
            it.spinnerImage.getLocationOnScreen(location)

            val dialogFragment =
                SeeAllSpinnerDialog(location[0], location[1])


            (seeAllContext as? FragmentActivity)?.supportFragmentManager?.let {
                dialogFragment.show(
                    it,
                    SeeAllSpinnerDialog.SPINNER_DIALOG
                )
            }
            }
}

"spinnerImage" is small image and I want to locate my custom spinner dialog under this view. My spinnerDialogFragment shortened code:

class SeeAllSpinnerDialog(var xPosition: Int,var yPosition: Int) : DialogFragment(), SpinnerListener {

......


  override fun onStart() {
        super.onStart()
        setDialogPosition()
    }

private fun setDialogPosition() {
    val window = dialog?.window
    val params = window?.attributes
    params?.x =
        xPosition
    params?.y =
        yPosition
    window?.attributes = params
}

}

So in my Customview on click I get the position x and y of the "spinnerImage" view, I send it to my spinnerDialog and use it to set the position. But this code does not work as expected, position is wrong.

to be more precise when I set code like thi for testing:

private fun setDialogPosition() {
        val window = dialog?.window
        val params = window?.attributes
        params?.x = 0
        params?.y = 0
        window?.attributes = params
    }

I would expect my view to be on the top left part of the custom view (android coordinate system (0,0) position is on top left. But instead it positions itself somewhere in the middle of the custom view.

I did positioning of views programatically before, what am I doing wrong in this example..? Thanks for help in advance!

2

There are 2 best solutions below

0
Kratos On BEST ANSWER

Well the only thing that was missing is the line:

window?.setGravity(Gravity.TOP or Gravity.START)

This way, my dialog starts at the top left part of screen and than the calculation:

 val params = window?.attributes
    params?.x =
        xPosition
    params?.y =
        yPosition
    window?.attributes = params

works like charm. I knew it is probably 1 or 2 line mistake since it worked before but it is usually like that in programming. Happy coding!

4
Pavlo Ostasha On

I don't think you need a dialog. Your use case could be completely covered by a PopupWindow - it is not a dialog but rather an arbitrary view that can be shown and anchored to a specific location or widget on the screen.

It is really easy to achieve use code like this to calculate needed view position on the screen:

val View?.viewRect: Rect?
    get() =
        this?.run {
            try {
                val location = IntArray(2)
                getLocationOnScreen(location)
                Rect().apply {
                    left = location[0]
                    top = location[1]
                    right = left + width
                    bottom = top + height
                }
            } catch (e: Exception) {
                null
            }
        }

And then just show a popup where it is needed:

private fun openSpinnerDialog() {
        binding?.let {
            val location = IntArray(2)
            it.spinnerImage.viewRect?.apply{
                // Instead of ... there should be a proper view inflation and other correct params of your desired popup
                PopupWindow(...).showAtLocation(parent, Gravity.TOP|Gravity.LEFT, left, bottom) // you can also use showAsDropDown for the dropdown like behaviour
            }
        }
}
popup.showAtLocation(parent, Gravity.TOP|Gravity.LEFT, location.left, location.bottom)

The code may need some adjustments as I've written it on the spot and never tested it.

By the way, location calculation could also apply to the dialog you want to show - I am not sure though.

Hope it helps.