I want to add a dots indicator as a decoration item to the RecyclerView

  Kiến thức lập trình

I am trying to add a dots indicator to the RecyclerView. My code is as follows.

val Int.dp: Int get() = (this * Resources.getSystem().displayMetrics.density).roundToInt()

class DotsIndicatorDecoration(
    @ColorInt colorInactive: Int,
    @ColorInt colorActive: Int
) : RecyclerView.ItemDecoration() {

    private val lineLength = 40.dp
    private val indicatorHeight: Int = 20.dp
    private val indicatorItemPadding: Int = 4.dp
    private val radius: Int = 2.dp
    private val inactivePaint = Paint()
    private val activePaint = Paint()

    init {
        inactivePaint.style = Paint.Style.FILL
        inactivePaint.isAntiAlias = true
        inactivePaint.color = colorInactive
        activePaint.style = Paint.Style.FILL_AND_STROKE
        activePaint.strokeCap = Paint.Cap.ROUND
        activePaint.strokeWidth = radius.toFloat() * 2
        activePaint.isAntiAlias = true
        activePaint.color = colorActive
    }

    override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        super.onDrawOver(c, parent, state)
        val adapter = parent.adapter ?: return
        val itemCount = adapter.itemCount

        val totalLength = (this.radius * 2 * itemCount).toFloat()
        val paddingBetweenItems = (0.coerceAtLeast(itemCount - 1) * indicatorItemPadding).toFloat()
        val indicatorTotalWidth = totalLength + paddingBetweenItems
        val indicatorStartX = (parent.width - indicatorTotalWidth) / 2f

        val indicatorPosY = parent.height - indicatorHeight / 2f

        val activePosition: Int = when (parent.layoutManager) {
            is LinearLayoutManager -> {
                (parent.layoutManager as LinearLayoutManager?)!!.findFirstCompletelyVisibleItemPosition()
            }
            else -> {
                return
            }
        }
        if (activePosition == RecyclerView.NO_POSITION) {
            return
        }

        drawInactiveDots(c, indicatorStartX, indicatorPosY, itemCount, activePosition)
        drawActiveLine(c, indicatorStartX, indicatorPosY, activePosition)
    }

    private fun drawInactiveDots(
        c: Canvas,
        indicatorStartX: Float,
        indicatorPosY: Float,
        itemCount: Int,
        activeIndex: Int,
    ) {
        val itemWidth = (this.radius * 2 + indicatorItemPadding).toFloat()
        var start = indicatorStartX + radius
        for (i in 0 until itemCount) {
            if (i == activeIndex) {
                start += lineLength / 2
                continue
            }
            c.drawCircle(start, indicatorPosY, radius.toFloat(), inactivePaint)
            start += itemWidth
        }
    }

    private fun drawActiveLine(
        c: Canvas, indicatorStartX: Float, indicatorPosY: Float,
        highlightPosition: Int
    ) {
        val itemWidth = (lineLength + indicatorItemPadding).toFloat() / 2
        val circleWidth = (radius * 2) + indicatorItemPadding
        val highlightStart = indicatorStartX + circleWidth * highlightPosition + radius
        c.drawLine(
            highlightStart,
            indicatorPosY,
            highlightStart + itemWidth - indicatorItemPadding / 2,
            indicatorPosY,
            activePaint
        )
    }

    override fun getItemOffsets(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {
        super.getItemOffsets(outRect, view, parent, state)
        outRect.bottom = indicatorHeight
    }
}

The expected appearance is as shown in the image below.example image

However, in the result I obtained, although there are scrollable items, the items that can be scrolled to are not visible, but the past items are visible. Additionally, during scrolling, the view disappears and reappears when scrolling finishes.

There is an item on the right side that can be scrolled to, but it is not visible
example image

It becomes visible when the selected item changes
example image

What I want is for all unselected items to be visible and for the selected item to be indicated with a line appearance. Also, I cannot understand why the view disappears during scrolling

New contributor

Frkclskn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

LEAVE A COMMENT