Hack RecyclerView.ItemDecoration

Hack RecyclerView.ItemDecoration

5f533179da1c82722252cbcb93e7356f?s=128

Moyuru Aizawa

April 12, 2019
Tweet

Transcript

  1. Hack RecyclerView.ItemDecoration @MoyuruAizawa

  2. MoyuruAizawa Moyuru Aizawa
 Software engineer of CATS Div. CyberAgent Inc.

    
 Previously at Pairs Div. Eureka Inc.
  3. RecyclerView.ItemDecoration

  4. ‣ An ItemDecoration allows the application to add a special

    drawing and layout offset to specific item views ‣ This can be useful for drawing dividers between items, highlights, visual grouping boundaries and more RecyclerView.ItemDecoration
  5. Divider

  6. override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State)

    { super.getItemOffsets(outRect, view, parent, state) if (parent.getChildLayoutPosition(view) < parent.childCount - 1) outRect.bottom = dividerWidth } Divider
  7. override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State)

    { super.getItemOffsets(outRect, view, parent, state) if (parent.getChildLayoutPosition(view) < parent.childCount - 1) outRect.bottom = dividerWidth } Divider
  8. override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State)

    { super.getItemOffsets(outRect, view, parent, state) if (parent.getChildLayoutPosition(view) < parent.childCount - 1) outRect.bottom = dividerWidth } Divider
  9. override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { super.onDraw(c,

    parent, state) (0 until parent.childCount) .mapNotNull(parent::getChildAt) .forEach { val left = it.left.toFloat() val right = it.right.toFloat() val bottom = it.bottom.toFloat() c.drawRect(left, bottom, right, bottom + dividerWidth, paint) } } Divider
  10. override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { super.onDraw(c,

    parent, state) (0 until parent.childCount) .mapNotNull(parent::getChildAt) .forEach { val left = it.left.toFloat() val right = it.right.toFloat() val bottom = it.bottom.toFloat() c.drawRect(left, bottom, right, bottom + dividerWidth, paint) } } Divider
  11. override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { super.onDraw(c,

    parent, state) (0 until parent.childCount) .mapNotNull(parent::getChildAt) .forEach { val left = it.left.toFloat() val right = it.right.toFloat() val bottom = it.bottom.toFloat() c.drawRect(left, bottom, right, bottom + dividerWidth, paint) } } Divider
  12. Timeline

  13. Timeline ItemDecoration

  14. Timeline

  15. Timeline

  16. Timeline

  17. Timeline

  18. override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State)

    { super.getItemOffsets(outRect, view, parent, state) outRect.left = width } Timeline
  19. override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { …

    (0 until parent.childCount) .mapNotNull(parent::getChildAt) .windowed(2, step = 2, partialWindows = true) .forEach { val text = "HH:mm" val top = it.first().top.toFloat() + margin val centerX = width / 2f val baseX = centerX - textPaint.measureText(text) / 2 val textBounds = Rect() .apply { textPaint.getTextBounds(text, 0, text.length - 1, this) } val baseY = top + textBounds.height() c.drawText(text, baseX, baseY, textPaint) c.drawLine(centerX, top + textBounds.height() + margin, centerX, it.last().bottom.toFloat(), linePaint) } } Timeline
  20. override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { …

    (0 until parent.childCount) .mapNotNull(parent::getChildAt) .windowed(2, step = 2, partialWindows = true) .forEach { val text = "HH:mm" val top = it.first().top.toFloat() + margin val centerX = width / 2f val baseX = centerX - textPaint.measureText(text) / 2 val textBounds = Rect() .apply { textPaint.getTextBounds(text, 0, text.length - 1, this) } val baseY = top + textBounds.height() c.drawText(text, baseX, baseY, textPaint) c.drawLine(centerX, top + textBounds.height() + margin, centerX, it.last().bottom.toFloat(), linePaint) } } Timeline
  21. override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { …

    (0 until parent.childCount) .mapNotNull(parent::getChildAt) .windowed(2, step = 2, partialWindows = true) .forEach { val text = "HH:mm" val top = it.first().top.toFloat() + margin val centerX = width / 2f val baseX = centerX - textPaint.measureText(text) / 2 val textBounds = Rect() .apply { textPaint.getTextBounds(text, 0, text.length - 1, this) } val baseY = top + textBounds.height() c.drawText(text, baseX, baseY, textPaint) c.drawLine(centerX, top + textBounds.height() + margin, centerX, it.last().bottom.toFloat(), linePaint) } } Timeline
  22. override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { …

    (0 until parent.childCount) .mapNotNull(parent::getChildAt) .windowed(2, step = 2, partialWindows = true) .forEach { val text = "HH:mm" val top = it.first().top.toFloat() + margin val centerX = width / 2f val baseX = centerX - textPaint.measureText(text) / 2 val textBounds = Rect() .apply { textPaint.getTextBounds(text, 0, text.length - 1, this) } val baseY = top + textBounds.height() c.drawText(text, baseX, baseY, textPaint) c.drawLine(centerX, top + textBounds.height() + margin, centerX, it.last().bottom.toFloat(), linePaint) } } Timeline
  23. override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { …

    (0 until parent.childCount) .mapNotNull(parent::getChildAt) .windowed(2, step = 2, partialWindows = true) .forEach { val text = "HH:mm" val top = it.first().top.toFloat() + margin val centerX = width / 2f val baseX = centerX - textPaint.measureText(text) / 2 val textBounds = Rect() .apply { textPaint.getTextBounds(text, 0, text.length - 1, this) } val baseY = top + textBounds.height() c.drawText(text, baseX, baseY, textPaint) c.drawLine(centerX, top + textBounds.height() + margin, centerX, it.last().bottom.toFloat(), linePaint) } } Timeline
  24. Timetable

  25. Timetable ItemDecoration

  26. Timetable

  27. Timetable

  28. Timetable

  29. Timetable

  30. Timetable

  31. override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { …

    val rightView = parent.children.maxBy { it.right } ?: return val rightColumnNumber = getColumnNumber(rightView.layoutPosition) val range = … var offsetX = rightView.right range.forEach { c.drawTextAtCenter(getColumnName(it), Rect(offsetX - columnWidth, 0, offsetX, height), textPaint) offsetX -= columnWidth } } Timetable
  32. override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { …

    val rightView = parent.children.maxBy { it.right } ?: return val rightColumnNumber = getColumnNumber(rightView.layoutPosition) val range = … var offsetX = rightView.right range.forEach { c.drawTextAtCenter(getColumnName(it), Rect(offsetX - columnWidth, 0, offsetX, height), textPaint) offsetX -= columnWidth } } Timetable
  33. override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { …

    val rightView = parent.children.maxBy { it.right } ?: return val rightColumnNumber = getColumnNumber(rightView.layoutPosition) val range = … var offsetX = rightView.right range.forEach { c.drawTextAtCenter(getColumnName(it), Rect(offsetX - columnWidth, 0, offsetX, height), textPaint) offsetX -= columnWidth } } Timetable
  34. override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { …

    val rightView = parent.children.maxBy { it.right } ?: return val rightColumnNumber = getColumnNumber(rightView.layoutPosition) val range = … var offsetX = rightView.right range.forEach { c.drawTextAtCenter(getColumnName(it), Rect(offsetX - columnWidth, 0, offsetX, height), textPaint) offsetX -= columnWidth } } Timetable
  35. Timetable

  36. Timetable ItemDecoration

  37. Timetable

  38. Timetable

  39. Timetable

  40. override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { …

    val startAtList = (0 until adapter.itemCount).map(this::getStartUnixMillis) val first = parent.children.minBy { it.top } ?: return val baseEpochMillis = startAtList.getOrNull(first.layoutPosition) ?: return startAtList .filterIndexed { i, startAt -> startAt >= baseEpochMillis && canDecorate(i) } .distinct() .forEach { startAt -> val gap = TimeUnit.MILLISECONDS .toMinutes(startAt - baseEpochMillis) * heightPerMinute val top = first.top + gap if (top > parent.height) return@forEach c.drawTextAtCenter( formatUnixMillis(startAt), Rect(0, top.toInt(), width, (top + textHeight).toInt()), textPaint ) } } Timetable
  41. override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { …

    val startAtList = (0 until adapter.itemCount).map(this::getStartUnixMillis) val first = parent.children.minBy { it.top } ?: return val baseEpochMillis = startAtList.getOrNull(first.layoutPosition) ?: return startAtList .filterIndexed { i, startAt -> startAt >= baseEpochMillis && canDecorate(i) } .distinct() .forEach { startAt -> val gap = TimeUnit.MILLISECONDS .toMinutes(startAt - baseEpochMillis) * heightPerMinute val top = first.top + gap if (top > parent.height) return@forEach c.drawTextAtCenter( formatUnixMillis(startAt), Rect(0, top.toInt(), width, (top + textHeight).toInt()), textPaint ) } } Timetable
  42. override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { …

    val startAtList = (0 until adapter.itemCount).map(this::getStartUnixMillis) val first = parent.children.minBy { it.top } ?: return val baseEpochMillis = startAtList.getOrNull(first.layoutPosition) ?: return startAtList .filterIndexed { i, startAt -> startAt >= baseEpochMillis && canDecorate(i) } .distinct() .forEach { startAt -> val gap = TimeUnit.MILLISECONDS .toMinutes(startAt - baseEpochMillis) * heightPerMinute val top = first.top + gap if (top > parent.height) return@forEach c.drawTextAtCenter( formatUnixMillis(startAt), Rect(0, top.toInt(), width, (top + textHeight).toInt()), textPaint ) } } Timetable
  43. override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { …

    val startAtList = (0 until adapter.itemCount).map(this::getStartUnixMillis) val first = parent.children.minBy { it.top } ?: return val baseEpochMillis = startAtList.getOrNull(first.layoutPosition) ?: return startAtList .filterIndexed { i, startAt -> startAt >= baseEpochMillis && canDecorate(i) } .distinct() .forEach { startAt -> val gap = TimeUnit.MILLISECONDS .toMinutes(startAt - baseEpochMillis) * heightPerMinute val top = first.top + gap if (top > parent.height) return@forEach c.drawTextAtCenter( formatUnixMillis(startAt), Rect(0, top.toInt(), width, (top + textHeight).toInt()), textPaint ) } } Timetable
  44. override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { …

    val startAtList = (0 until adapter.itemCount).map(this::getStartUnixMillis) val first = parent.children.minBy { it.top } ?: return val baseEpochMillis = startAtList.getOrNull(first.layoutPosition) ?: return startAtList .filterIndexed { i, startAt -> startAt >= baseEpochMillis && canDecorate(i) } .distinct() .forEach { startAt -> val gap = TimeUnit.MILLISECONDS .toMinutes(startAt - baseEpochMillis) * heightPerMinute val top = first.top + gap if (top > parent.height) return@forEach c.drawTextAtCenter( formatUnixMillis(startAt), Rect(0, top.toInt(), width, (top + textHeight).toInt()), textPaint ) } } Timetable
  45. override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { …

    val startAtList = (0 until adapter.itemCount).map(this::getStartUnixMillis) val first = parent.children.minBy { it.top } ?: return val baseEpochMillis = startAtList.getOrNull(first.layoutPosition) ?: return startAtList .filterIndexed { i, startAt -> startAt >= baseEpochMillis && canDecorate(i) } .distinct() .forEach { startAt -> val gap = TimeUnit.MILLISECONDS .toMinutes(startAt - baseEpochMillis) * heightPerMinute val top = first.top + gap if (top > parent.height) return@forEach c.drawTextAtCenter( formatUnixMillis(startAt), Rect(0, top.toInt(), width, (top + textHeight).toInt()), textPaint ) } } Timetable
  46. ‣ %JWJEFSͷඳըʹศར ‣ ͦͷؾʹͳΕ͹ଟ࠼ͳ%FDPSBUJPO͕Մೳ ‣ PO%SBX PO%SBX0WFS͸εΫϩʔϧͷͨͼʹ࣮ߦ͞ΕΔͷͰॏ͍ॲཧ ͸޲͍͍ͯͳ͍Ͱ͢ ‣ ಉ༷ʹɺΠϯελϯεͷੜ੒΋ͳΔ΂͘ݮΒͨ͠΄͏͕ྑ͍

    Hack RecyclerView.ItemDecoration
  47. Thank you