0

I'm using data binding to setup a RecyclerView. Here is the binding adapter:

fun setRecyclerDevices(recyclerView: RecyclerView, items: List<Device>, itemBinder: MultipleTypeItemBinder,
                                   listener: BindableListAdapter.OnClickListener<Device>?) {

        var adapter = recyclerView.adapter as? DevicesBindableAdapter
        if (adapter == null) {
            val spannedGridLayoutManager = SpannedGridLayoutManager(orientation = SpannedGridLayoutManager.Orientation.VERTICAL,
                    spans = getSpanSizeFromScreenWidth(recyclerView.context, recyclerView))
            recyclerView.layoutManager = spannedGridLayoutManager
            recyclerView.addItemDecoration(SpaceItemDecorator(left = 15, top = 15, right = 15, bottom = 15))
            adapter = DevicesBindableAdapter(items, itemBinder)
            adapter.setOnClickListener(listener)
            recyclerView.adapter = adapter
        } else {
            adapter.setOnClickListener(listener)
            adapter.setItemBinder(itemBinder)
            adapter.setItems(items)
        }
    }

getSpanSizeFromScreenWidth needs the recycler's width to do some calculation. But it always returns 0.

I tried to apply a ViewTreeObserver like this:

recyclerView.viewTreeObserver.addOnGlobalLayoutListener(object: ViewTreeObserver.OnGlobalLayoutListener {

                override fun onGlobalLayout() {
                    recyclerView.viewTreeObserver.removeOnGlobalLayoutListener(this)
                    val spannedGridLayoutManager = SpannedGridLayoutManager(orientation = SpannedGridLayoutManager.Orientation.VERTICAL,
                            spans = getSpanSizeFromScreenWidth(recyclerView.context, recyclerView))
                    recyclerView.layoutManager = spannedGridLayoutManager
                }
            })

Or use post like this:

recyclerView.post({
                val spannedGridLayoutManager = SpannedGridLayoutManager(orientation = SpannedGridLayoutManager.Orientation.VERTICAL,
                        spans = getSpanSizeFromScreenWidth(recyclerView.context, recyclerView))
                recyclerView.layoutManager = spannedGridLayoutManager
            })

Code of getSpanSizeFormScreenWidth:

private fun getSpanSizeFromScreenWidth(context: Context, recyclerView: RecyclerView): Int {
        val availableWidth = recyclerView.width.toFloat()
        val px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 300f, context.resources.displayMetrics)
        val margin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 15f, context.resources.displayMetrics)
        return Math.max(1, Math.floor((availableWidth / (px + margin)).toDouble()).toInt()) * DevicesBindableAdapter.WIDTH_UNIT_VALUE
    }

But it still returns 0 despite my RecyclerView being displayed on the screen (not 0).

Any ideas?

jaumard
  • 8,202
  • 3
  • 40
  • 63

1 Answers1

0

In inspecting the code, it appears that your RecyclerView may actually be fine, but your logic in getSpanSizeFromScreenWidth may not be.

It looks like this: Math.floor((availableWidth / (px + margin)).toDouble()).toInt() will always be 0 when availableWidth is less than (px + margin). This will then cause getSpanSizeFromScreenWidth to return 0.


Breaking it down:

  • Math.floor - rounds a double down to a whole number
  • availableWidth / (px + margin) - will be a low number (a fraction of availableWidth)

Therefore, you're going to get 0 at times especially on smaller screens and/or smaller density screens.

Does that make sense? May not be this issue, but I'd start there. It's hard to tell you exactly the issue without knowing the whole context, but that's likely your issue.


If that is not your issue, could you say what your value is for availableWidth, px, and margin during execution?

Joshua King
  • 3,450
  • 1
  • 17
  • 19
  • But my problem is that with the debugger recycler.width is equal to 0 not the all function :/ so availableWidth = 0, px= 825.0 and margin = 15.0 – jaumard Nov 07 '17 at 08:37
  • 1
    Maybe my calculation is wrong for small screen and density you're right, but here I'm testing on a big screen and density so should be right. But thanks I'll take a look for smaller densities when this one is fixed ^^ – jaumard Nov 07 '17 at 08:42
  • Hold on.. I somehow completely missed the `Math.max(1, ...)`. But that means that the last line would **have** to resolve to ` * DevicesBindableAdapter.WIDTH_UNIT_VALUE`. And if you said it's returning `0`, then that means that either `WIDTH_UNIT_VALUE` equals `0` or it is `> 0 and < 0.5` potentially causing it to round down to `0`. Hopefully that helps. Haha if not, good luck! Hope you get it working.. P.S. this post may have some similar ideas to try: https://stackoverflow.com/questions/3591784/getwidth-and-getheight-of-view-returns-0?rq=1 – Joshua King Nov 07 '17 at 09:11
  • 1
    No getSpanSizeFromScreenWidth always return 8 because WIDTH_UNIT_VALUE equal 8 :) but that's because my recyclerView.width always return 0 :( I'll keep digging but thanks but your inputs :) – jaumard Nov 07 '17 at 10:41