Как я могу добиться волнового эффекта при просмотре на холсте в RecyclerView.ItemDecoration? - PullRequest
0 голосов
/ 07 ноября 2019

Я создал нижний колонтитул в RecyclerView, переопределив RecyclerView.ItemDecoration (). Он содержит кнопку изображения со стрелкой, направленной вверх, и нарисован на холсте.

Я хочу добиться эффекта ряби при нажатии кнопки изображения.

Footer

Я хотел бы воспользоваться советами о том, как было бы намного проще просто добавить элемент другого типа в список. Я не могу использовать этот способ, так как он сталкивается с другими частями кода. Поэтому я должен придерживаться этого решения.

FooterItemDecorator

private const val SCROLL_TO_TOP_ICON_SIZE_IN_DP = 52

class FooterItemDecorator(
        context: Context,
        parent: RecyclerView,
        val onFooterClicked: () -> Unit
) : RecyclerView.ItemDecoration() {

    private val footerView = LayoutInflater.from(context).inflate(R.layout.item_scroll_to_top, parent, false)
    private var iconBounds: IconBounds? = null

    private val onFooterTouchListener = object: RecyclerView.OnItemTouchListener {
        override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {}

        override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
            if (e.action == MotionEvent.ACTION_UP && iconBounds?.iconClicked(e.x, e.y) == true) {
                onFooterClicked()
            }
            return false
        }

        override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
    }

    init {
        footerView.measure(makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
                makeMeasureSpec(0, MeasureSpec.UNSPECIFIED))
        parent.addOnItemTouchListener(onFooterTouchListener)
    }

    override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        super.onDraw(c, parent, state)

        footerView.layout(parent.left, 0, parent.right, footerView.measuredHeight)

        val adapterItemsCount = parent.adapter?.itemCount ?: -1

        if (adapterItemsCount > 1) {
            for (i in 0 until parent.childCount) {
                val view = parent.getChildAt(i)

                if (parent.getChildAdapterPosition(view) == adapterItemsCount - 1) {
                    c.save()
                    c.translate(0F, view.bottom.toFloat())
                    footerView.draw(c)
                    if (iconBounds == null) {
                        iconBounds = getIconBounds(parent.bottom, footerView.measuredHeight, parent.right)
                    }
                    c.restore()
                    break
                }
            }
        }
    }

    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
        val itemsCount = parent.adapter?.itemCount ?: -1
        if (itemsCount > 1 && parent.getChildAdapterPosition(view) == itemsCount - 1) {
            outRect.set(0, 0, 0, footerView.measuredHeight)
        } else {
            outRect.setEmpty()
        }
    }
}

private data class IconBounds(
        val left: Int,
        val top: Int,
        val right: Int,
        val bottom: Int
)

private fun IconBounds.iconClicked(touchX: Float, touchY: Float)
        = touchX.toInt() in left..right && touchY.toInt() in top..bottom

private fun getIconBounds(parentBottom: Int, footerHeight: Int, recyclerWidth: Int): IconBounds {
    val footerTop = parentBottom - footerHeight
    val iconHorizontalCenter = recyclerWidth / 2
    val iconVerticalCenter = footerTop + (footerHeight / 2)
    val iconRadius = (SCROLL_TO_TOP_ICON_SIZE_IN_DP / 2).dpToPx()
    return IconBounds(
            left = iconHorizontalCenter - iconRadius,
            top = iconVerticalCenter - iconRadius,
            right = iconHorizontalCenter + iconRadius,
            bottom = iconVerticalCenter + iconRadius
    )
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...